怎样才能制定一项出色的人工智能策略来玩五子棋?

15

我正在编写一个变体的五子棋游戏,基本上是在一个巨大的棋盘上玩井字棋。

想知道是否有人知道这个游戏的好的人工智能策略。我的当前实现非常愚蠢,需要很长时间(O(n^3),大约1-2秒才能走一步):

-(void) moveAI {
    //check if the enemy is trying to make a line horizontally, vertically, or diagonally
    //O(n^3 * 3)
    [self checkEnemies];

    //check if we can make a line horizontally, vertically, or diagonally
    //O(n^3 * 3)
    [self checkIfWeCanMakeALine];

    //otherwise just put the piece randomly
    [self put randomly];
}
6个回答

23

1
需要注意的一点是:五子棋已经被解决了,但它的更高级版本——连珠棋并没有。连珠棋基本上是在游戏中添加开局和禁手规则以使其更加平衡。但要编写一个好的连珠程序,你必须先编写一个好的五子棋程序 :) - Rauni Lillemets
哇,非常感谢Tomas!我正在编写一个相当重要的Gomoku变体,基本上游戏不会在某人连成五个时结束。游戏将在有人得分5分时结束。因此,在这种情况下可能会有一些不同之处(例如,如果您看到某人有4个开放的位置,请不要费心,只需尝试用我们自己的棋子得分)。 - Enrico Susatyo
@the_great_monkey 也许您可以写更多关于您正在为其编写AI的游戏?正如您所说,当一个人连成5个时游戏并不会结束 - 这使得我之前关于五子棋策略的回答变得无用了。 :) - Rauni Lillemets
@Rauni 不,事实上你的回答帮了很多忙。从所有答案中我得到的一个关键点是,我只需要看对手的最后一步棋。我的先前算法检查整个棋盘(这就是为什么它需要O(n^3)的原因),但只检查最后一步是否形成了开放的三连或四连,使算法更加高效。 - Enrico Susatyo
2
@Rauni 只有标准版的五子棋被解决了,而 Swap2 没有。而 Swap2 是专业五子棋的标准。 - Peter Porfy

15
传统且相当有效的编写此类游戏AI的策略是典型的树搜索策略。也就是说,每个棋盘状态形成了一个图中的节点,并在每个节点和可以通过单个移动得到的状态之间放置有向边。这样就建立了一棵以空节点为根的树。然后,以某种聪明的方式遍历树,找到看起来像是“好”的状态。通常,通过使用一些巧妙的启发式评估函数来衡量“好”的状态。显然,您不想访问树中的所有节点--那将是很多工作! 您只需要一些聪明的东西。
您可以添加预先计算的早期和结束游戏来加速这些场景,然后依靠经过优化的树遍历启发式算法来处理中游戏阶段。
这种树遍历算法的实际名称是“极小极大”算法。在维基百科上查找它,您会看到很多相当不错的资料。还有一些提高算法效率的方法,其中最显著的是Alpha-Beta剪枝,请确保您查看了它。您可能需要查看Connect Four启发式算法,并决定如何将它们应用于您的游戏。例如,评估棋盘状态的一个可能很好的启发式方法是计算可继续的2-连、3-连和4-连的数量,并将它们加权到分数中(例如,每个2-连值1分,每个3-连值10分,每个4-连值1000分)。
另一个优化策略是开发一种启发式,它优先考虑极小极大算法应该搜索哪里--通常是通过估计某种程度上确定性的棋盘评估函数来实现。

使用这种策略,你应该能在同样的时间内得到不太愚蠢的AI。然而,真正非常出色的AI需要付出很多努力才能构建,即使在这些“简单”的游戏中,仍可能需要花费10秒或更长的时间才能找到聪明的方法。另一方面,有一些巧妙的编程技巧,比如在人类对手忙于思考时预先计算树形结构的遍历路径。嘿,人类可以思考,而计算机也可以思考,公平竞争!


4
好的评论。不过,计算五子棋的终局并不现实。这在国际象棋和跳棋中可行,因为由于只剩下少数几个棋子,终局的计算要容易得多。然而,在五子棋中,棋子的数量会增加(每一步都会新增一枚棋子),所以这种方式不奏效。 - Rauni Lillemets

8
Gomoku已经被解决,但在开局位置和资源有限的情况下进行游戏时尚未解决。
我是Hewer gomoku程序的作者和Gomocup组织者,我可以告诉你,编写优秀的Gomoku AI需要很长时间。Renju更加复杂。您可以使用Gomocup接口简化工作并仅编写AI。

qub1n: 你能详细说明一下在这个上下文中,“opening”和“limited resources”的含义吗?更普遍地说,在五子棋及其相关游戏的分析中有哪些有趣的未解决问题? - user1604015
1
有限的资源意味着内存和时间的限制。我喜欢Piskvork(http://sourceforge.net/projects/piskvork/)锦标赛管理器中的规则。玩家们进行两场游戏,有限制的内存、移动时间和游戏时间。如果是平局,那么胜利者是在“思考”上花费更少时间的AI。 - Tomas Kubes

7

我一直在尝试为同一个程序创建算法。

当然,你的程序首先应该做的事情是检查是否有方法可以形成五子连珠并获胜。如果没有,下一步应该检查对手是否能够这样做,如果可以,那么进行防守。

你自己玩过gomoku吗?你对基本规则有多好的掌握?

好的,下一步是思考:我们如何到达可以获胜的位置?显然,要获胜,我们必须有四个棋子连成一排。但是如果我们只是像这样形成四子连珠:

__________
____XOOOO_
__________

然后对手就可以关闭它。

但是如果我们形成“开放四个”,像这样:

__________
____OOOO__
__________

对手无法同时封住两边,你就能赢。因此,形成一个“开放四”的棋型是获胜的一种方式。那么问题来了:我们如何形成一个“开放四”呢?当然,如果我们形成“开放三”,就像这样:

__________
____OOO___
__________

然后对手就可以阻止我们:

___________
____XOOO___
___________

我们回到了起点。

为了赢得比赛,我们可以同时形成两个开放的三连:

____________
____OOO_____
_____O______
____O_______

现在如果对手堵住其中一个,我们可以使用另一个来形成一个开放四:
____________
_______O____
___XOOO_____
_____O______
____O_______
____________

并且获胜:

________O___
_______O____
___XOOO_____
_____O______
____O_______
___X________

在五子棋中,如果您同时制造了两个开放的三连,这被称为3x3。请注意,两个三连都必须是开放的:您能理解为什么吗?
还有其他赢的方法:
4x3:您看到了获胜的步骤以及它为什么能赢吗?
____________
__XOOO______
__XXXO______
____OX______
____________

4x4:看到获胜的走法了吗?

____________
__XOOO______
__XXXO______
__OXOX______
___O________
__X_________

这只是游戏基础。了解策略有助于您思考如何构建人工智能,因此您可以硬编码原则。
当然,这只是个开始。如果您能尝试实施并向我反馈,我将不胜感激。
我一直在尝试用Java编写程序。您想看看我已经完成的代码,以便进行玩家测试吗?它还不是很好,但您可以从中获得新的想法。虽然注释和变量名是用爱沙尼亚语书写的...可能很难理解。 :(

是的,我认为如果您能够分享您的代码,那将是有益的。 - Eerik Sven Puudist

5

我曾经创建过一个五子棋玩家,使用了alpha-beta剪枝算法,并根据每个位置上双方拥有的半开放和完全开放的2、3、4个棋子来给出得分。

计算这些得分并不是n^3。你只需要检查最新的落子是否关闭了对手的任意一条线路,是否扩展了自己的某些线路,然后相应地修改得分。

如果你想让它玩得更好,可以考虑一些来自国际象棋电脑的技巧。例如,在搜索时首先尝试“杀手着法”(记住哪些着法在其他位置上得分高或直接获胜),这样会显著提高树搜索的效率。在alpha-beta剪枝中,尝试假设最佳着法非常重要。

当你拥有了自己的玩家后,你应该尝试找出哪种不同元素(2、3、4、开放和半开放等)的得分最好,通过让不同版本之间互相对战来实现。


1
我也创建了我的五子棋玩家。它并不完美,但它能下出相当不错的棋,并且肯定比我更好。无论如何,我发现:
  • 如果玩家使用深度搜索,寻找正确移动的搜索应该限制在特定的棋盘位置上。一种朴素的方法是仅搜索相邻的棋子位置。另一种方法是仅包括产生“威胁”的移动,例如开放2、开放3等。然后只包括防御性的移动来阻止进攻移动。这种启发式显着减少了要搜索的节点数。如果我理解正确,类似的方法用于减少搜索空间来解决五子棋。
  • 然而,五子棋的分支因子很高,如果玩家找不到获胜序列,它必须选择“最佳”可能移动之一。定义“最佳”的启发式对于AI玩家的工作非常重要。

因此,我的五子棋玩家评估所有棋盘位置,没有深度搜索。它将水平、垂直和对角线的棋盘线划分为字符串。然后在这些字符串中搜索模式。对于黑方玩家,其中一些模式是:

  1. xxxxx:分数10000000000
  2. -xxxx-:9999999
  3. -xxx-:50
  4. -xx-:500
  5. ooooo:-100000000
  6. -oooo-:-99999999
  7. -ooo--:-999999
  8. -oo-:-2000

X表示黑方棋子,O表示白方棋子,"-"表示空位。玩家计算并加总所有发现的形状,并作出最高得分的移动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接