如何使用Minimax算法和Alpha Beta剪枝解决4×4的井字游戏

我制作了一个井字游戏,使用了Minimax算法和Alpha Beta剪枝。我原本想为10×10的井字游戏设计一个电脑AI,但其游戏树的规模大得离谱。

我的代码设计使得只需更改两个变量就能改变棋盘大小和获胜所需的连续格数。例如:

boardSize = 3 // 这是3x3的井字游戏

boardSize = 4 // 这是4x4的井字游戏

boardSize = 10 // 这是10x10的井字游戏

winStreak = 3 // 需要连续3格获胜

winStreak = 4 // 需要连续4格获胜

希望你能明白我的意思。

因此,我将计划从10×10的井字游戏改为3×3的,运行得很好。

然后我将boardSize设为4,winStreak设为3,变成了4×4的井字游戏。

我原本以为Minimax算法加上Alpha Beta剪枝足以解决4×4的游戏,但结果让我惊讶,它并不够用。

当我(人类)做出第一步棋时,Minimax算法需要搜索5到10分钟,然后浏览器标签页就崩溃了。它甚至无法完成第一步棋的计算。

我该如何提高其速度?人们甚至能够使用Minimax和Alpha Beta剪枝解决国际象棋,但我的代码哪里出了问题?

我的完整代码大约有200到300行,所以我只写伪代码。

humanMakeMove();Minimax(); // 机器人调用Minimax函数来走棋function Minimax(board, player) {if (checkResult() != 0) // 0 = 游戏进行中   return checkResult(); // 1 = 赢, 0.5 = 平局, -1 = 输      availableMoves = getAvailableMoves();   for(i = 0; i < availableMoves.length;i++)   {        move = availableMoves[i];         removeMoveFromAvailableMovesArray(move);        if (player == "X")            score = Minimax(board, "O");        else            score = Minimax(board, "X");        board[i] = "-"; // "-"表示空格        if (树的深度在第一层 && score == 1)                return maxScore; // 在这里应用Alpha Beta剪枝,如果得分是1,则无需继续搜索。    }}

我还能应用哪些优化措施来使代码运行得更快?


回答:

有几种方法可以提高你程序的性能。

  1. 评估函数。看起来你目前只在达到终端游戏节点时才应用评估函数。在像3×3井字游戏这样的小型游戏中,这是一种合理的方法,因为搜索树很小,叶节点可以在短时间内从起始位置到达。但对于在大型棋盘上进行的游戏(如国际象棋、围棋等),你无法递归直到达到终端节点(这将耗费太长时间)。因此,你需要决定在哪个递归深度停止,并尝试根据游戏的战术/战略原则评估当前位置。为了做到这一点,你需要编写一个启发式评估函数来给出位置的价值。然后,你可以将这个值传播到搜索树上,以确定最佳走法。整个程序的质量可能在很大程度上依赖于评估函数的质量。
  2. 走法排序。在生成所有有效走法的列表后,根据评估函数按降序排序。这样,算法将首先考虑更好的走法,这些走法更可能产生高alpha-beta剪枝,导致更多节点被剪枝。
  3. 迭代加深与主要变体搜索。不要直接用固定深度调用minimax函数,而是先用深度1调用,然后是2,3,…(在达到每步时间限制时停止)。存储在深度k时找到的最佳走法,并在深度k + 1的minimax中用作第一个候选走法。此外,你还可以存储不仅仅是最佳走法,而是最佳走法的整个序列,这称为主要变体。因此,在找到深度k的主要变体后,将其输入到深度k + 1的minimax调用中,这通常会产生很多好的alpha-beta剪枝。
  4. 开局库。如果你知道前几步(甚至可能是几十步)好的走法,你可以将它们硬编码到开局库中。因此,当你的程序遇到开局库中的位置时,它将立即检索最佳答案。一个简单的开局库示例是在3×3井字游戏中将第一步硬编码到中心方格。这样,你的程序将花零秒找到第一步走法。
  5. 转置表。尝试重用在minimax搜索期间为位置X找到的最佳走法,以确定与X对称的位置Y的最佳走法(意味着Y可以通过旋转/反射从X获得)。在棋盘游戏编程中实现转置表的常见高级技术之一称为Zobrist哈希。
  6. 并行算法。尝试并行化你的算法,以使其在多核机器上运行得更快。
  7. 编程语言。由于你的问题标记有Javascript标签,我假设你使用这种语言来实现算法。Javascript在性能方面不被认为是最佳语言。因此,如果你熟悉C、C++或Java等语言,将程序重写成其中一种语言可以显著提高性能。

最后,你的这句话

人们甚至能够使用Minimax + Alpha Beta剪枝解决国际象棋

严格来说是不正确的,因为国际象棋尚未被解决。但确实存在能够轻松击败人类玩家的国际象棋程序(使用minimax与alpha-beta剪枝以及许多其他更高级的技术)。因此,程序能够击败专家玩家和世界冠军并不意味着它玩得完美无缺。

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注