16

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のコードを更新して、完全に機能するようになりました。

4

1 に答える 1

9

それが最もエレガントな方法かどうかはわかりませんが、ここでは 2 段階のフォークの見方を示します。

コンピューターが次のターンに勝てず、1 ターン目でも 2 ターン目でもない場合、フォークが発生する可能性があります (これは、フォークのセットアップを作成することではなく、フォークを見つけるだけです)。

空のセルごとに入力し、ステップ 1 の関数を実行します (2 つ連続しているかどうかを確認します)。2 つの場所が見つかった場合は、おめでとうございます。フォークがあります。そうでなければ、あなたはしません。

于 2011-11-28T05:05:10.893 に答える