Я уже читал много тем 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: Причина, по которой я говорю, что она не идеальна, - это (сначала идет процессор, а его ячейки голубые, клетки человека - красные). Как вы можете видеть, если я помещаю в верхнюю ячейку, компьютер выигрывает. Но если я поместил в правую ячейку, это галстук, хотя компьютер все равно может выиграть.
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, теперь он отлично работает!