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

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

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

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, теперь он отлично работает!

4b9b3361

Ответ 1

Я не уверен, что это самый элегантный способ сделать это, но вот двухэтапный взгляд на вилки.

Если компьютер не может выиграть следующий поворот, и это не первый или второй поворот, возможно, будет вилка (это не касается создания установки для вилки, просто нахождение вилки).

Для каждой из ячеек, которые пусты, заполните его, а затем запустите функцию шага 1 (видит, есть ли две строки). Если он найдет два места, поздравляю, у тебя есть вилка. Если нет, вы этого не сделаете.