- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我已经在 StackOverflow 上阅读了许多 Tic Tac Toe 主题。我发现维基百科上的策略适合我的演示项目:
A player can play perfect tic-tac-toe if they choose the move with the highest priority in the following table[3].
1) Win: If you have two in a row, play the third to get three in a row.
2) Block: If the opponent has two in a row, play the third to block them.
3) Fork: Create an opportunity where you can win in two ways.
4) Block Opponent's Fork:
Option 1: Create two in a row to force the opponent into defending, as long as it doesn't result in them creating a fork or winning. For example, if "X" has a corner, "O" has the center, and "X" has the opposite corner as well, "O" must not play a corner in order to win. (Playing a corner in this scenario creates a fork for "X" to win.)
Option 2: If there is a configuration where the opponent can fork, block that fork.
5) Center: Play the center.
6) Opposite Corner: If the opponent is in the corner, play the opposite corner.
7) Empty Corner: Play an empty corner.
8) Empty Side: Play an empty side.
我按照这些步骤操作,计算机从未丢失。然而,它的攻击方式并不完美。因为我不知道如何执行第 3 步。这是我在第 3 步中所做的:扫描每个单元格,检查将 token 放在该单元格上是否会创建一个 fork ,然后将其放在那里。
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中也使用了该方法,所以countFork<中有一个 token 参数
函数)。
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 中的代码,现在它完美运行了!
最佳答案
我不确定这是最优雅的方法,但这是查看 fork 的两步方法。
如果计算机无法在下一回合获胜,并且不是第一回合或第二回合,则可能会出现 fork (这不涉及为 fork 创 build 置,只是找到 fork )。
对于每个空的单元格,填充它,然后运行您的第 1 步函数(查看是否有两个连续的单元格)。如果它找到两个地方,恭喜,你有一个 fork 。如果没有,你就没有。
关于c# - Tic Tac Toe完美AI算法: deeper in "create fork" step,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8287084/
大家好,我知道这段代码的作用: 1.]我的第一个问题 x = 4 y = x 但是这个呢。为什么即使在这种情况下也使用相同的地址? x = 4 y = 4 id(x) 12345678 id(y) 1
我正在使用 SFML 2.3 来控制程序中的图形。我需要一个类才能访问窗口,即使该类不是最初创建窗口的类(没有所有权)也可以绘制它。例如。 Battle 类需要能够绘制战斗场景并在那里操作角色,但是
我不知道该如何描述?我认为如果你看看我制作的 jsfiddle 会更好.. 如您所见,某些 TR 元素上有悬停,如果 TD 已经有另一个 bgcoler,它必须更改为替代 bgcolor.. 它在前
我的意思是,虽然你可以这样做: $foo = "Yo dawg I herd you like $bar->baz"; 这个: $foo = "Yo dawg I herd you like $bar
首先。对不起我的标题,我已经考虑了十多分钟我要命名我的问题。但是我什么也没得到.. 在我的应用程序中,我有三个基本属于彼此的组件。 我有: Doors.js DoorsItem.js DoorsDet
我第一次尝试响应式编程,使用 bacon.js ,并遇到了一个让我很烦的奇怪的互动。我想出了这个事件链的一个工作版本,但是 hackish 的额外流操作使它从其余代码中脱颖而出——如您所见。 我发现
在 PhpStorm 中,如果我创建了一个对象,那么该对象的所有自动完成功能都可以正常工作: $object = new MyClass(); $object->getNa... 将自动完成 $obj
假设我想高效地从 xml 文档中选择所有 field 节点。该文档可能如下所示:
在 Angular2 中有没有办法为异步代码获得更好的调用堆栈?我一直认为跟踪 setTimeout()、发出的事件、Promises 等的执行上下文是 Zone 的优势之一? 我构建了一个 plun
我的模型相关如下: Post BELONGS_TO Parent Parent HAS_MANY ParentAdmin 现在,如果满足帖子的属性值,我希望找到所有帖子的所有父级管理员。等效的 sql
几年前,我和我的兄弟为 Mandelbrot 集编写了 Java 代码。昨天我想用它找到一些很酷的变焦,但当我进行更强烈的变焦时,我开始注意到一个问题(变焦值约为 1E14)。像素似乎被组合在一起,有
我已经在 StackOverflow 上阅读了许多 Tic Tac Toe 主题。我发现维基百科上的策略适合我的演示项目: A player can play perfect tic-tac-toe
这个问题在这里已经有了答案: Convert a JavaScript string in dot notation into an object reference (34 个答案) 关闭 5 年
除了开发人员工具网络面板提供的功能之外,我如何更深入地了解网络浏览器的网络级别发生了什么?例如,我现在正尝试在 Firefox (18.0.1) 中调试页面上的一个问题,在页面加载完成后加载“微调器”
我是一名优秀的程序员,十分优秀!