/// <summary> /// ツモを落下させフィールド情報を更新する /// </summary> /// <param name="pp">ツモ</param> public void Drop(ColorPairPuyo pp) { int pos = pp.Pos - 1; if (pp.Dir == Direction4.UP) { DropOne(pp.Pivot, pos); DropOne(pp.Satellite, pos); } else if (pp.Dir == Direction4.DOWN) { DropOne(pp.Satellite, pos); DropOne(pp.Pivot, pos); } else if (pp.Dir == Direction4.LEFT) { DropOne(pp.Pivot, pos); DropOne(pp.Satellite, pos - 1); } else { DropOne(pp.Pivot, pos); DropOne(pp.Satellite, pos + 1); } }
/// <summary> /// ネクストのデバッグ枠を表示する /// </summary> /// <param name="g">グラフィックオブジェクト</param> /// <param name="field">ネクスト状態</param> private void DrawDebugNext(Graphics g, CaptureField field) { ColorPairPuyo pp = field.Next; for (int y = 0; y < 2; y++) { PuyoType type = pp[y]; Rectangle rect = field.GetNextRect(0, y); DrawDebugRect(g, type, rect); } }
/// <summary> /// ネクスト画像を解析する /// </summary> /// <param name="bmp">解析する画像</param> /// <returns>ネクスト状態</returns> private CaptureField AnalyzeNext(Bitmap bmp) { CaptureField field = new CaptureField(); RapidBitmapAccessor ba = new RapidBitmapAccessor(bmp); ba.BeginAccess(); ColorPairPuyo pp = new ColorPairPuyo(); for (int y = 0; y < 2; y++) { pp[y] = detector.Detect(ba, field.GetNextRect(0, y)); } field.Next = pp; ba.EndAccess(); return(field); }
/// <summary> /// カレントツモを決定する /// </summary> /// <returns>カレントの組ぷよ</returns> private ColorPairPuyo DecideCurNext() { // ツモの待機中に一番長い間検出されていた色の組み合わせを現在のツモとする // これによりツモ移動中による誤判定の確率を減らすことができる ColorPairPuyo next = (from n in currents where n.Value == (from nn in currents select nn.Value).Max() select n.Key).ElementAt(0); if (currents.Count > 1) { LOGGER.Debug("ツモ候補が2つありました。"); foreach (KeyValuePair <ColorPairPuyo, int> pair in currents) { LOGGER.Debug(pair.Key.Pivot + " " + pair.Key.Satellite + " :" + pair.Value); } } LOGGER.Debug("確定ツモ:" + next.Pivot + " " + next.Satellite); return(next); }
/// <summary> /// ぷよ譜のレコード状況を進める /// </summary> /// <param name="curField">現在のフィールドの状態</param> /// <param name="next">ネクスト組ぷよ</param> /// <returns>処理結果</returns> public RecordResult DoNext(CaptureField curField, ColorPairPuyo next) { if (IsRecordEnded) { return(RecordResult.RECORD_ENDED); } if (!isRecording) { return(RecordResult.NOT_RECORDING); } if (steps.Count >= captureStepNum) { isRecording = false; IsRecordSucceeded = true; IsRecordEnded = true; return(RecordResult.RECORD_SUCCESS); } if (next.Pivot != PuyoType.NONE && next.Satellite != PuyoType.NONE) { // ネクストぷよがネクスト領域にセットされ待ち状態になっている時の処理 if (!currents.ContainsKey(next)) { currents[next] = 0; } currents[next]++; isReadyForNextStepRecord = true; return(RecordResult.RECORDING); } else if (next.Pivot == PuyoType.NONE && next.Satellite == PuyoType.NONE && !isReadyForNextStepRecord2) { // ネクストぷよが設定されていない時の処理 if (!isReadyForNextStepRecord) { // ネクストぷよはセット⇒ツモの順に行われるため、それに該当しないようなものは無視する return(RecordResult.RECORDING); } // ここに来るのはネクストがツモられた瞬間のみ curNext = DecideCurNext(); if (captureOnlyTsumo) { // ツモのみキャプチャする場合は、確定したツモを譜情報に追加し、次のツモ処理に戻る if (prevNext == null) { // 初手の場合 prevNext = curNext; isReadyForNextStepRecord = false; currents = new Dictionary <ColorPairPuyo, int>(); curNext = null; return(RecordResult.RECORD_FORWARD); } else { // 2手目以降 // 譜の情報を追記し、次のツモの処理待ち状態に戻す steps.Add(prevNext); prevNext = curNext; isReadyForNextStepRecord = false; currents = new Dictionary <ColorPairPuyo, int>(); curNext = null; captureFailCount = 0; return(RecordResult.RECORD_FORWARD); } } else { isReadyForNextStepRecord2 = true; } } if (isReadyForNextStepRecord2) { // ネクストがツモられた後、前のツモがどこに設置されたか判定できるまでここが呼ばれる if (prevNext == null) { // 初手の場合 prevNext = curNext; isReadyForNextStepRecord = false; isReadyForNextStepRecord2 = false; currents = new Dictionary <ColorPairPuyo, int>(); curNext = null; return(RecordResult.RECORD_FORWARD); } else { // 2手目以降 ColorPairPuyo prevStep = prevField.GetStepFromDiff(curField, prevNext); if (prevStep != null) { // 前ツモをどこにおいたか確定できた場合 LOGGER.Debug(prevStep.Pivot + " " + prevStep.Satellite + " " + prevStep.Dir + " " + prevStep.Pos); // 譜の情報を追記し、次のツモの処理待ち状態に戻す steps.Add(prevStep); prevField.Drop(prevStep); prevNext = curNext; isReadyForNextStepRecord = false; isReadyForNextStepRecord2 = false; currents = new Dictionary <ColorPairPuyo, int>(); curNext = null; captureFailCount = 0; return(RecordResult.RECORD_FORWARD); } else { LOGGER.Info("前回:\n" + prevField); LOGGER.Info("今回:\n" + curField); captureFailCount++; // 計1秒以上譜が特定できなければ失敗とする if (captureFailCount > (1000 / captureInterval)) { isRecording = false; IsRecordFailed = true; IsRecordEnded = true; return(RecordResult.RECORD_FAILURE); } } } } return(RecordResult.RECORDING); }
/// <summary> /// ネクストの再描画処理 /// </summary> /// <param name="sender">イベント発生源</param> /// <param name="e">イベント情報</param> /// <param name="fieldNo">フィールド番号</param> private void PaintNext(object sender, PaintEventArgs e, int fieldNo) { if (!IsCapturing) { return; } PictureBox nextImg = (PictureBox)sender; Graphics nextG = e.Graphics; using (Bitmap forAnalyzeBmp = new Bitmap(nextImg.Width, nextImg.Height)) using (Graphics forAnalyzeG = Graphics.FromImage(forAnalyzeBmp)) { // ネクストのキャプチャ範囲を取り込む Rectangle nextRect = captureRects.GetNextRect(fieldNo); //取り込んだ画像を解析用のBMPに出力 Rectangle dest = new Rectangle(0, 0, 32, 64); Rectangle src = new Rectangle() { X = nextRect.X - captureRects.CaptureRect.X, Y = nextRect.Y - captureRects.CaptureRect.Y, Width = nextRect.Width, Height = nextRect.Height }; forAnalyzeG.DrawImage(screenBmp, dest, src, GraphicsUnit.Pixel); // 取り込んだ画像を画面に出力 nextG.DrawImage(forAnalyzeBmp, dest, dest, GraphicsUnit.Pixel); // ツモ情報を解析し、結果を描画 CaptureField field = AnalyzeNext(forAnalyzeBmp); if (config.DebugRectEnabled) { DrawDebugNext(nextG, field); } ColorPairPuyo next = field.Next; RecordResult result = recorders[fieldNo].DoNext(curFields[fieldNo], next); switch (result) { case RecordResult.RECORD_SUCCESS: updateRecordDataTxt(); break; case RecordResult.RECORD_FAILURE: statusLabel.Text = "キャプチャ失敗!!"; updateRecordDataTxt(); break; case RecordResult.RECORD_FORWARD: stepRecordTxts[fieldNo].Text = recorders[fieldNo].GetStepRecord(); break; case RecordResult.RECORD_ENDED: updateRecordDataTxt(); break; default: break; } } }
/// <summary> /// キャプチャ範囲の差分からツモの設置情報を特定する /// </summary> /// <param name="f2">ツモを設置後のキャプチャフィールド</param> /// <param name="pp">設置したツモ</param> /// <returns>ツモの設置情報</returns> public ColorPairPuyo GetStepFromDiff(CaptureField f2, ColorPairPuyo pp) { CaptureField f1 = this; bool foundPivot = false; bool foundSatellite = false; ColorPairPuyo p2 = new ColorPairPuyo(); Point pivotPt = new Point(-1, -1); Point satellitePt = new Point(-1, -1); for (int x = 0; x < X_MAX; x++) { for (int y = 0; y < Y_MAX; y++) { PuyoType pt1 = f1.GetPuyoType(x, y); PuyoType pt2 = f2.GetPuyoType(x, y); if (pt1 != pt2) { if (!foundPivot && pp.Pivot == pt2) { p2.Pos = x; p2.Pivot = pt2; foundPivot = true; pivotPt.X = x; pivotPt.Y = y; } else if (pp.Satellite == pt2) { p2.Satellite = f2.GetPuyoType(x, y); foundSatellite = true; satellitePt.X = x; satellitePt.Y = y; } else { return(null); } if (foundPivot && foundSatellite) { if (pivotPt.X == satellitePt.X && pivotPt.Y < satellitePt.Y) { p2.Dir = Direction4.UP; } else if (pivotPt.X == satellitePt.X) { p2.Dir = Direction4.DOWN; } else if (pivotPt.X < satellitePt.X) { p2.Dir = Direction4.RIGHT; } else { p2.Dir = Direction4.LEFT; } p2.Pos++; return(p2); } } } } return(null); }