TicTacToe AI 做出不正确的决定

Posted

技术标签:

【中文标题】TicTacToe AI 做出不正确的决定【英文标题】:TicTacToe AI Making Incorrect Decisions 【发布时间】:2010-12-24 13:19:57 【问题描述】:

一点背景知识:作为在 C++ 中学习多节点树的一种方式,我决定生成所有可能的井字棋盘并将它们存储在树中,这样从节点开始的分支都是可以从该节点跟随的所有棋盘,并且一个节点的子节点是一步跟随的棋盘。在那之后,我觉得用那棵树作为决策树来写一个玩井字游戏的 AI 会很有趣。

TTT 是一个可解决的问题,完美的玩家永远不会输,所以我第一次尝试 AI 时,似乎很容易编写 AI。

现在,当我第一次实现 AI 时,我返回并在生成时为每个节点添加了两个字段:X 将获胜的次数和 O 在该节点下的所有子节点中获胜的次数。我认为最好的解决方案是让我的 AI 在每一步中选择并沿着获胜次数最多的子树向下走。然后我发现虽然它在大多数情况下都表现完美,但我找到了可以击败它的方法。这不是我的代码有问题,只是我让 AI 选择路径的方式有问题。

然后我决定让它选择计算机获得最大胜利或人类损失最大的树,以较大者为准。这使它表现更好,但仍然不完美。我仍然可以击败它。

所以我有两个想法,我希望输入哪个更好:

1) 我可以指定值 1 表示胜利,0 表示平局,-1 表示失败,而不是最大化胜利或失败。然后选择具有最高值的树将是最好的移动,因为下一个节点不能是导致损失的移动。这是板生成中的一个简单更改,但它保留了相同的搜索空间和内存使用。或者……

2) 在棋盘生成过程中,如果有棋盘使得 X 或 O 在下一步中获胜,则只会生成阻止该获胜的子棋盘。不会考虑其他子节点,然后生成将照常进行。它缩小了树的大小,但是我必须实现一个算法来确定是否有单步获胜,我认为这只能在线性时间内完成(我认为让棋盘生成速度慢很多?)

哪个更好,或者有更好的解决方案?

【问题讨论】:

赢的唯一方法就是不玩。 【参考方案1】:

基于决策树实现 AI 的(通常)正确方法是使用“Minimax”算法:

    为每个叶节点分配一个分数(+1=玩家获胜,-1=玩家失败,0=平局)

    沿着树往上走,对每个节点应用以下规则:

    对于均匀深度(当玩家移动时),选择得分最高的孩子,并将该得分复制到节点。 对于奇数深度(当计算机会移动时),选择得分最低的孩子,并将该得分复制到节点。

当然,偶数和奇数可能需要颠倒,这取决于你决定谁先走。

您可以在以下位置阅读更多内容:

http://ai-depot.com/articles/minimax-explained/ http://en.wikipedia.org/wiki/Minimax

【讨论】:

我开始写关于 MinMax 的文章,然后我看到添加了一个新答案 - 这与我想说的内容相似! :-) 所以+1给你。还有一点:这种方法在博弈论中决策树的解法中很常见——这个井字游戏可以看成是这样的“游戏”。所以我也推荐阅读博弈论。首先,因为它很有趣,其次因为它可能是相关的。 这是正确答案。最小-最大的概念是人工智能的基础,也是每个喜欢编程的人都应该学习的聪明点之一。【参考方案2】:

您现有的算法很好,除了您忘记了一件事。永远不要选择任何其他玩家的举动导致您无法至少平局的路径。

因此,基本上,丢弃玩家下一步可能导致无法平局的任何分支,然后运行您现有的算法。这样可以最大程度地战胜不完美的对手,同时消除失败的可能性。

【讨论】:

【参考方案3】:

井字游戏可以使用greedy algorithm 来解决,实际上并不需要决策树。

如果您想继续使用当前的算法,请按照 patros 的建议进行操作,并尽量减少在每个决定中失败的可能性。

如果您想要更简单的方法,让 AI 每回合执行以下操作:

    如果可能的话,完成一个获胜的井字游戏。 如果可能,阻止对方的井字游戏。

    对每个方格的可取性进行评分,对于在一条线上(由 AI)取的每个方格,为该方格添加一个可取点。对于对手占据的每一个方格,移除一个期望值。

    例如,如果板子当前是:

    _|O|X
    _|X|_
    O| |
    

    左上角的合意性为 0(1 表示同一行中的 X,1 表示对角线中的 X,但每个 Os 为 -1)。

    在最理想的方格上玩。随意断绝关系。

    在上面的示例中,AI 会选择右中方格,因为它的合意性为 2,这将导致下一回合获胜。

    如果比赛刚刚开始,就玩中间方格,如果中方方格被占据,随机选择一个角。

    获胜(或平局)。

这是我 10 年级的 Visual Basic 学期项目。与存储决策树相比,它不可能被击败,并且需要的内存要少得多。

【讨论】:

我意识到井字游戏很简单,可以通过这种方式解决,但其他游戏则不然。用树解决它的目的是为了经验。 :) 你能澄清一下“为对方在一条线上(由人工智能)采取正方形”吗?很难解析那条线。 :-) @Frank,我在算法中添加了一些内容,并举例说明了如何计算合意性。 @Chris:我是这么想的,但我还是给你一个替代解决方案,因为你问是否有更好的解决方案。【参考方案4】:

执行此操作的“幼稚”方法(对于两个玩家轮流移动的任意游戏)是递归地尝试每个可能的移动,直到最终得到一个赢家的棋盘,然后向上回溯在树中将节点标记为“O 胜”、“X 胜”或“平局”。

每次你走上一步(这样的一步通常称为 ply),根据谁的走法,假设玩家选择了最适合他/她的走法。由于您是从叶子节点向上移动,因此您将始终知道每个子节点的最佳可能结果。

当计算子树中可能输赢棋盘的个数时,您基本上是在假设每个玩家总是会随机移动。正如您所指出的,如果您与聪明的玩家对战,这将不是很有效。相反,我在上面概述的方案假设对手总是做出完美的举动,试图获胜。

【讨论】:

以上是关于TicTacToe AI 做出不正确的决定的主要内容,如果未能解决你的问题,请参考以下文章

课堂练习(团队)

Java 中的 2D Arrays TicTacToe 游戏.. 验证问题

神操作!只需5行代码,就能做出一个图像识别AI

在 Python 中,我无法使用 PIL 正确打开一些 png 图像

TicTacToe Java 检查抽奖

Data LakeHouse概览