【问题标题】:Simple tic-tac-toe AI [closed]简单的井字游戏 AI [关闭]
【发布时间】:2013-04-01 23:19:25
【问题描述】:

我知道这个问题被问了很多,我也搜索了其他代码,但我看到的大部分代码似乎都不是完美无缺的(永远不会丢失),而且简单、优雅和高效。而且我无法确定哪种类型的解决方案适合该描述。

我见过的解决方案是:

(1) 使用带有 alpha-beta 修剪的 minimax。这对我来说似乎很复杂,对于这样一个简单的游戏来说可能是不必要的?是不是太复杂了?如果不是,我需要做很多硬编码还是我误解了算法?

(2) 使用 Wikipedia 中的伪代码策略编写代码...我不确定如何实现。例如,它只是说“检查分叉”。这些检查中的大多数是否会通过拥有一系列winningLines并检查它们是否会被填写或类似的东西来完成?如果没有,有人可以给我关于什么数据结构的提示或关于如何在此处实现伪代码中提出的检查的任何基本提示:http://en.wikipedia.org/wiki/Tic-tac-toe#Strategy。我还看到了一些算法,它们为“X”方和“O”方提供数值,然后使用总和来决定获胜者,但我不明白为什么这特别有用。

还有其他合理的解决方案吗?

【问题讨论】:

  • 对于这么小的游戏树,只需暴力破解它。模拟所有可能的游戏完全不需要时间。
  • 似乎并非完美无瑕(总是获胜)= 似乎很正常。我总是在井字游戏中获胜。或者最坏的关系。任何聪明的人都会有同样的结果。这就是为什么没有人在 10 岁之后玩井字游戏。没有人赢就不好玩。
  • 另外,“总是赢”不是一个有效的要求(永远)。想象一下你的算法与自己对抗。
  • 那么您可能应该编辑您的问题。
  • Minimax 并不一定很复杂,对于这么小的游戏来说,剪枝并不是真正需要的。参见例如this implementation

标签: javascript artificial-intelligence tic-tac-toe


【解决方案1】:

说实话,在处理 AI 和启发式算法时,最简单的任务很快就会变得复杂。极小极大方法将为您提供最佳结果,考虑到您正在实施人工智能这一事实,这应该不会太难。它是基于 2 人回合的游戏逻辑的既定标准。

查看这个网站...它对井字游戏 AI 和 minimax 实现提供了一些很好的见解。

http://www.ntu.edu.sg/home/ehchua/programming/java/JavaGame_TicTacToe_AI.html

编辑:

注意到有人写了“蛮力”……这最终会成为实现极小极大启发式算法的一种低效方式。根据其他玩家的最后一步迭代每一个可能的移动只是实现启发式的另一种方式......除了在我看来,它似乎是更多的工作。 Minimax 实现将简单而有效。

编辑2:

“更简单的实现”是相对的。 Minimax 是标准,正如我在评论中所说,您可以操纵启发式以适应您正在寻找的情况......

我希望我能告诉你最简单的方法,但是有很多变量取决于你的游戏在代码中的植入。

接受建议,看看你的游戏实现,然后看看最适合你的!

对一个人来说简单的事情对另一个人来说可能很复杂。我只是想为您提供选择,而极小极大非常可靠。也许尝试调整它以满足您的需求。

编辑3:

如果您需要更多指导,请告诉我。我很乐意提供帮助。

【讨论】:

  • 明确地说,您是说 minimax 实际上最终比检查 wikipedia 条目中的所有案例更简单,还是说它并不复杂同时还允许更高效和优雅的代码?
  • 我的意思是如果你想要动态播放,请使用 minimax。在井字游戏的情况下,使用 wiki 中的案例,您可以对这些选项进行硬编码,并根据需要以“蛮力”方式遵循它们。它可以正常工作并保证在某些情况下获胜。我是说如果你想要一个通用的启发式来处理案例,你可以用你的特定启发式来实现极小值。您可以在启发式中包含那些“确定获胜”的案例,以确保它们被覆盖,然后在需要时退回到更一般的选择。我认为包含两者的混合启发式方法对您最有用。
  • “在某些情况下保证获胜”是什么意思。它不能保证在所有情况下都获胜吗?
  • 是的。对不起,如果我不完全清楚。语义...
【解决方案2】:

使用您选择的格式将this image“编码”成一组动作。 AI 总是会赢或打平。

例如,您可以将其编码如下:

var turns = {
  "mefirst":{
    "move":0,
    "next":[
      null,
      {
        "move":4,
        "next":[
          null,
          null,
          {"move":8}, // win
          {"move":8}, // win
          null,
          {"move":8}, // win
          {"move":8}, // win
          {"move":8}, // win
          {
            "move":6,
            "next":[
              null,
              null,
       /* AND SO ON... */
    ]
  }
};

然后你可以开始:

if( ai_goes_first) {
    game = turns.mefirst;
    makeMove(game.move);
}
else game = turns.themfirst;
playerTurn();

playerTurn 类似于:

function playerTurn() {
    when player clicks a valid squeare {
        game = game.next[chosenSquare];
        makeMove(game.move);
        if( game.next) playerTurn();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    • 2019-12-07
    • 2023-03-16
    • 1970-01-01
    相关资源
    最近更新 更多