如何使用Minimax Algorithem和Alpha Beta修剪解决Tic Tac Toe 4x4游戏

时间:2018-07-19 15:57:26

标签: javascript machine-learning tic-tac-toe minimax alpha-beta-pruning

我使用Minimax和Alpha Beta Pruning制作了Tic Tac Toe游戏。我想为井字游戏(10x10)游戏制作计算机AI,但是它的游戏树很大。

我的代码是这样的,我只需要更改两个变量即可更改连续赢取所需的Board Size + Cells。 示例:

boardSize = 3 // This is for 3x3 tic tac toe

boardSize = 4 // This is for 4x4 tic tac toe

boardSize = 10 // This is for 10x10 tic tac toe

winStreak = 3 // Need to make 3 cells in a row to win

winStreak = 4 // Need to make 4 cells in a row to win

我希望你明白了。

因此,我将我的Tic Tac Toe的计划从10x10更改为3x3,并且效果很好。

然后我更改boardSize = 4winStreak = 3,使其成为(4x4)井字游戏。

现在,我认为带有Alpha Beta修剪功能的Minimax足以解决4x4的问题,但是很惊讶地看到,事实并非如此。

当我迈出第一步(人类)时,minimax算法会搜索5-10分钟,然后浏览器标签就会崩溃。它甚至无法迈出第一步。

如何提高速度?人们甚至可以使用Minimax + Alpha Beta修剪来解决国际象棋,但是我的代码有什么问题呢?

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

humanMakeMove();

Minimax(); // Bot calls Minimax function to make a move

function Minimax(board, player) {
if (checkResult() != 0) // 0 = Game is on
   return checkResult(); // 1 = Win, 0.5 = Draw, -1 = Lose   

   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] = "-"; // "-" means empty space


        if (depth of tree is on first level && score == 1)
                return maxScore; //Alpha Beta Pruning is applied here, if we get score of 1, then we don't need to search more. 


   }
}

还有什么我可以应用的优化方法来使代码运行更快?

1 个答案:

答案 0 :(得分:2)

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

  1. 评估功能。似乎当前您仅在到达终端游戏节点时才应用评估功能。在3x3井字游戏中,这是一种合理的方法,因为搜索树很小,并且可以在短时间内从起始位置到达叶子节点。但是,对于在较大的棋盘上进行的游戏(如国际象棋,围棋等),您直到到达终端节点都无法递归(这将花费太多时间)。因此,您需要确定要停止的递归深度,并尝试根据游戏的战术/策略原则评估当前位置。为此,您需要编写一个启发式评估函数,该函数将为您提供头寸的价值。然后,您可以将该值沿搜索树传播,以确定最佳移动。整个程序的质量在很大程度上取决于评估函数的质量。
  2. 运动顺序。。生成所有有效运动的列表后,请根据评估功能对它们进行降序排列。这样,该算法将首先考虑良好的举动,这些举动更有可能产生较高的alpha-beta截止值,从而导致修剪更多的节点。
  3. 通过主变量搜索进行迭代加深。而不是首先以某个固定深度调用minimax函数,而是尝试先以深度1,然后2、3,...(在停止时停止)进行调用达到每次移动截止的时间)。存储在深度为k的minimax中找到的最佳移动,并将其用作深度为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修剪来解决国际象棋

严格说来,

并不是真的,因为国际象棋还没有解决。但是,存在一些可以轻易击败人类玩家的国际象棋程序(使用带有alpha-beta修剪功能的minimax和许多其他更先进的技术)。因此,程序可以打败专家级选手和世界冠军的事实并不意味着它的表现完美。