この辛抱強いゲームのボットは既に存在します ( 1つではありません )が、転送プロトコルを監視せず、他の誰かのコードを選択して実装したいのですが、それらに基づいてパターン認識と意思決定、つまり実際のプレーヤーのアクションの何らかのエミュレーションを実装しようとしました。 楽しみのためだけにマタンはありません。 habrokatの下での.NETでの実装。
ゲーム内のブロックは静的( アニメーション化されていない )スプライトであり、ハードポジショニングがあります。 最も簡単な方法は、各ブロックの位置をピクセル単位で測定し、手動で作成したテンプレートを使用してそれらを決定することです。 しかし、特にこのような方法はこのゲームに厳密に結び付けられるため、面白くて退屈なものではありません。 そのため、ボットを作成することにしました。ボットは( 部分的に )運動場の位置とその上の要素を決定します。
そのため、まず、すべての可能な要素を強調する必要があります。 合計で、そのうちの5つが判明しました*。 ペイントで切り取り、フォルダに保存します。 次に、運動場の幅と高さ、水平および垂直に配置される要素の数を決定する必要があります。
これらの要素は、画面上で検索する必要があります。 実際には、フィールドの少なくとも1つが最初に会うところから始まります。 フィールドの位置を決定する必要があるのは一度だけです-ゲームの開始時に、この部分の速度について考えすぎる理由はありません。 ピクセルごとの比較が長すぎるため、そのような精度は必要ないため、要素のスプライトの最も明確なポイントを選択します( 中央のどこかにあります )。 次に、スクリーンのスクリーンショットを取得し、そのピクセルを探します。 ピクセルが見つかった場合、見つかったピクセルが目的の要素に属しているかどうかを確認します。
最初に見つかった要素は、競技場の最初の境界を意味します。 この要素の検索を短縮するために、画面全体を削除するのではなく、ユーザーに競技場のおおよその領域を提供します(このために透明なメインフォームを使用しました)。
さらに簡単です。フィールドを断片に分割し、それぞれを既存のブロックに一致させる必要があります。 これを行うために、各ブロックの「平均」色とフィールドの「ピース」の平均色を決定し、それらを比較します**。
C#コード
//"" //detail - . private Color getMidColor(Bitmap inpBit, int x, int y, int w, int h, int detail) { double r = 0, g = 0, b = 0; for (var ii = x; ii < x + w; ii += detail) for (var jj = y; jj < y + h; jj += detail) { var pix = inpBit.GetPixel(ii, jj); r += pix.R; g += pix.G; b += pix.B; } r /= (w * h / detail / detail);// :-( g /= (w * h / detail / detail); b /= (w * h / detail / detail); return Color.FromArgb((int)r, (int)g, (int)b); } // // //blcColors - "" . private int colorCompare(Color c) { int max=255; int cur = -1; int imax; for(var i=0;i<blcColors.Count;i++) { imax=Math.Abs(cR - blcColors[i].R) + Math.Abs(cG - blcColors[i].G) + Math.Abs(cB - blcColors[i].B) / 3; if (imax < max) { max=imax; cur = i; } } if (max > 50)// return -1;// return cur; }
次に、ブロックのマトリックスを作成し、その上にある接触ブロックの最大部分(深さ)を探します。 タスクは簡単で、迷路から抜け出す方法を見つけるのに少し似ています。
//..... for (var i = 0; i < 10; i++) for (var j = 0; j < 9; j++) { if (nots[i, j])// count[i, j] = // "" searching(i, j, 0); // "" if(count[i, j]>max) { x=i; y=j; max = count[i, j]; } } //..... // private int searching(int i, int j, int c) { nots[i, j] = false; // for (var di = -1; di <= 1; di++) for (var dj = -1; dj <= 1; dj++) if (di+i >= 0 && di+i < 10 && dj+j >= 0 && dj+j < 9) // ? if (Math.Abs(di) != Math.Abs(dj)) // ? if (cube[i, j] == cube[i + di, j + dj]) // ? if (nots[i + di, j + dj]) // ? { c = searching(i + di, j + dj, c+1); // ! } return c; } }
シェルとフォームのコードはおそらく意味がありません。画面上に競技場が見つかったら、タイマーを開始します(たとえば、1/4秒)。 タイマーがトリガーされると、「最も深い」ブロックを特定し、画面上でクリックします 。
ボットの例。 さらに、プログラムが合計でブロック認識と意思決定に15〜20ミリ秒を費やしても、あまり意味がありません。 私のウィンドウでは、フラッシュドライブは既にわずかな10〜20 fpsを生成し、ビデオの撮影ではスライドショーになります。 ボットが300kを満たせる最大数。
____
*実際、それらは6つありましたが、ボットを追加して初めてこのことを知りました。 彼が自分でプレイしたとき(ひどく)、このブロックは現れませんでした。
** 2、4、またはそれ以上のブロックに分割することはできましたが、ここでは不要でした。