我已经在 StackOverflow 上阅读了许多井字游戏主题。我发现维基百科上的策略适合我的演示项目:
如果玩家选择下表[3]中优先级最高的着法,则玩家可以玩完美的井字游戏。
1) 获胜:如果你连续获得两个,则玩第三个以获得连续三个。
2)阻挡:如果对手连续两个,打第三个来阻挡他们。
3)分叉:创造一个机会,你可以通过两种方式获胜。
4) 阻止对手的分叉:
选项 1:连续制造两个以迫使对手防守,只要这不会导致他们制造分叉或获胜。例如,如果“X”有角球,“O”有中锋,而“X”也有对角角,则“O”必须不打角球才能获胜。(在这种情况下打角球会为“X”赢得一个分叉。)
选项 2:如果存在对手可以分叉的配置,则阻止该分叉。
5)中锋:打中锋。
6) 对角:如果对手在角,打对角。
7)空角:打一个空角。
8) Empty Side:玩空的一面。
我已经按照这些步骤操作了,计算机永远不会丢失。但是,它的攻击方式并不完美。因为我不知道如何执行第 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 将计算计算机有多少个fork(计算机的token为2,玩家token为1,因为我在第4步也使用了该方法,所以函数中有token的参数countFork
)。
EDIT2:我说它不完美的原因是这个(CPU先走,它的细胞是蓝色的,人体细胞是红色的)。
如您所见,如果我放入顶部单元格,则计算机获胜。但是如果我输入右边的单元格,那就是平局,尽管计算机仍然可以获胜。
EDIT3:不知道为什么,但我注释掉了第 3 步,并且电脑播放......完美!我真的很惊讶!这是我的countFork函数(我需要将此代码移植到不支持二维数组的Alice,所以我使用getNumberFromXY将二维数组转换为一维):
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 更新了代码,现在它可以完美运行了!