StackOverflowでTicTacToeのトピックをたくさん読んだことがあります。そして、ウィキペディアの戦略が私のプレゼンテーションプロジェクトに適していることがわかりました。
次の表[3]で最も優先度の高い動きを選択すると、プレーヤーは完璧な三目並べをプレイできます。
1)勝つ:2つ続けて持っている場合は、3番目をプレイして3つ続けてください。
2)ブロック:対戦相手が2つ続けている場合は、3番目をプレイしてブロックします。
3)フォーク:2つの方法で勝つことができる機会を作成します。
4)対戦相手のフォークをブロックする:
オプション1:2つ続けて作成し、フォークを作成したり勝利したりしない限り、対戦相手に防御を強制します。たとえば、「X」にコーナーがあり、「O」に中央があり、「X」にも反対側のコーナーがある場合、「O」は勝つためにコーナーをプレイしてはなりません。(このシナリオでコーナーをプレイすると、「X」が勝つためのフォークが作成されます。)
オプション2:対戦相手がフォークできる構成がある場合は、そのフォークをブロックします。
5)センター:センターを再生します。
6)反対側のコーナー:対戦相手がコーナーにいる場合は、反対側のコーナーをプレイします。
7)空のコーナー:空のコーナーを再生します。
8)空のサイド:空のサイドをプレイします。
私はこれらの手順を実行しましたが、コンピューターが失われることはありません。しかし、それが攻撃する方法は完璧ではありません。手順3の方法がわからないため、手順3で行う方法は次のとおりです。すべてのセルをスキャンし、そのセルにトークンを置くとフォークが作成されるかどうかを確認してから、そこに置きます。
private void step3() // Create Fork.
{
int[] dummyField = (int[])field.Clone();
// Try Level 1 Dummy
for (int i = 0; i < 9; i++)
{
if (dummyField[i] != 0) continue;
dummyField[i] = 2;
if (countFork(dummyField, 2) >= 2)
{
nextCell = i;
return;
}
dummyField[i] = 0;
}
}
このステップについてアドバイスをお願いします。
編集1:カウントフォークは、コンピューターが持っているフォークの数をカウントします(コンピューターのトークンは2、プレーヤートークンは1です。これは、ステップ4でもそのメソッドを使用したため、countFork
関数内にトークンのパラメーターがあります)。
EDIT2:私がそれが完璧ではないと言う理由はこれです(CPUが最初に行き、その細胞は青で、人間の細胞は赤です)。
ご覧のとおり、上面のセルに入れると、コンピューターが勝ちます。しかし、右側のセルを入れると、コンピューターは勝つことができますが、それは引き分けです。
EDIT3:理由はわかりませんが、ステップ3をコメントアウトすると、コンピューターが再生されます...完全に!びっくり!これが私のcountFork関数です(このコードを2次元配列をサポートしないAliceに移植する必要があるため、getNumberFromXYを使用して2次元配列を1次元に変換します):
private int countFork(int[] field, int token)
{
int result = 0;
// Vertical
int cpuTokenCount;
int spareCell;
for (int x = 0; x < 3; x++)
{
cpuTokenCount = 0;
spareCell = -1;
for (int y = 0; y < 3; y++)
{
if (field[getNumberFromXY(x, y)] == token)
cpuTokenCount++;
else if (field[getNumberFromXY(x, y)] == 0)
spareCell = getNumberFromXY(x, y);
}
if (cpuTokenCount == 2 && spareCell != -1) result++;
}
// Horizontal
for (int y = 0; y < 3; y++)
{
cpuTokenCount = 0;
spareCell = -1;
for (int x = 0; x < 3; x++)
{
if (field[getNumberFromXY(x, y)] == token)
cpuTokenCount++;
else if (field[getNumberFromXY(x, y)] == 0)
spareCell = getNumberFromXY(x, y);
}
if (cpuTokenCount == 2 && spareCell != -1) result++;
}
// Top-Left To Lower-Right Diagonal
cpuTokenCount = 0;
spareCell = -1;
for (int i = 0; i < 3; i++)
{
if (field[getNumberFromXY(i, i)] == token)
cpuTokenCount++;
else if (field[getNumberFromXY(i, i)] == 0)
spareCell = getNumberFromXY(i, i);
}
if (cpuTokenCount == 2 && spareCell != -1) result++;
// Top-Right To Lower-Left Diagonal
cpuTokenCount = 0;
spareCell = -1;
for (int i = 0; i < 3; i++)
{
if (field[getNumberFromXY(2 - i, i)] == token)
cpuTokenCount++;
else if (field[getNumberFromXY(2 - i, i)] == 0)
spareCell = getNumberFromXY(2 - i, i);
}
if (cpuTokenCount == 2 && spareCell != -1) result++;
return result;
}
EDIT4:soandosによるバグを修正し、EDIT 3のコードを更新して、完全に機能するようになりました。