Tic Tac Toe идеальный алгоритм искусственного интеллекта: глубже на шаге "создать вилку"

Я уже прочитал много тем по Tic Tac Toe на StackOverflow. И я нашел стратегию в Википедии, которая подходит для моего презентационного проекта:

Игрок может играть в идеальный крестики-нолики, если он выбирает ход с наивысшим приоритетом в следующей таблице[3].

1) Выиграть: Если у вас есть два хода подряд, сыграйте третий, чтобы получить три хода подряд. подряд.

2) Блокировать: Если у противника есть два хода подряд, сыграйте третий ход, чтобы заблокировать их.

3) Вилка: Создайте возможность, когда вы можете выиграть двумя способами.

4) Блокировать вилку противника:

Вариант 1: Создайте две вилки подряд, чтобы заставить противника защищаться, при условии, что если это не приведет к созданию вилки или выигрышу. Для Например, если "X" имеет угол, "O" имеет центр, и "X" имеет противоположный угол, "О" не должен играть в угол, чтобы выиграть. (Игра в угол в этом сценарии создает вилку для победы "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;
    }

}

Пожалуйста, дайте мне совет по поводу этого шага.

EDIT1: Функция count fork будет считать, сколько вилок есть у компьютера (токенов компьютера - 2, токенов игрока - 1, потому что я использовал этот метод и для шага 4, поэтому в функции countFork есть параметр token).

EDIT2: Причина, по которой я говорю, что это не идеально, заключается в следующем (процессор идет первым, и его клетки синие, клетки человека - красные). enter image description here Как вы можете видеть, если я помещу ячейку сверху, компьютер выиграет. Но если я поставлю правую клетку, то будет ничья, хотя компьютер все равно может победить.

EDIT3: Не знаю почему, но я закомментировал шаг 3, и компьютер играет... отлично! Я очень удивлен! Вот моя функция countFork (мне нужно перенести этот код на Alice, которая не поддерживает 2-мерные массивы, поэтому я использую 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, теперь он работает идеально!

16
задан Martijn Pieters 27 March 2013 в 08:53
поделиться