将Minimax转换为Negamax(python)

2 投票
1 回答
4058 浏览
提问于 2025-04-18 09:14

我正在制作一个黑白棋的玩家,已经实现了一个带有α-β剪枝的极小极大算法。然后我在网上做了很多研究,发现大家都在提到一个叫“负极大”(negamax)的算法。似乎大多数人认为负极大比极小极大要快(我觉得是因为它不需要在最小和最大玩家之间切换?),所以如果不太难的话,我想把我的极小极大算法改成负极大。

我想知道使用负极大究竟快多少,还有没有人能给我一些建议或者代码,帮我把我的极小极大代码改成负极大的算法,这样我会很感激!

这是我的极小极大算法:

def minimax(Board, maximizingPlayer, depth, count):
     # maximizing player has 'B' and minimizing 'W'
     if maximizingPlayer: player, opp = Board.player, Board.opp
     else: player, opp = Board.opp, Board.player

     moves_list = Board.get_moves_list(player, opp)
     best_move = (-1,-1)

     # base case
     if ( depth==0 or moves_list == [] ):
         best_score, parity, mobility, stability = Board.evaluate()
         best_move = (-1, -1)
         return best_score, best_move, count

     # maximizing player
     if maximizingPlayer:
           best_score = float("-inf")
           for move in moves_list:
                new_board = deepcopy(Board)
                new_board.play_legal_move(move[0], move[1], player, opp, flip=True)
                the_score, the_move, count = minimax(new_board, False, depth-1, count+1)
                best_score = max(best_score, the_score)
                if (the_score == best_score):
                    best_move = move

           return best_score, best_move, count
     # minimzing player
     else:
           best_score = float("inf")
           for move in moves_list:
                new_board = deepcopy(Board)
                new_board.play_legal_move(move[0], move[1], player, opp, flip=True)
                the_score, the_move, count = minimax(new_board, True, depth-1, count+1)
                best_score = min(best_score, the_score)
                if (the_score == best_score):
                    best_move = move

           return best_score, best_move, count

因为有人问我关于α-β剪枝的事,这里是相关内容:

def alphabeta(Board, maximizingPlayer, depth, count, alpha, beta):
     # maximizing player has 'B' and minimizing 'W'
     if maximizingPlayer: player, opp = Board.player, Board.opp
     else: player, opp = Board.opp, Board.player

     moves_list = Board.get_moves_list(player, opp)
     best_move = (-1,-1)

     # base case
     if ( depth==0 or moves_list == [] ):
         best_score, parity, mobility, stability = Board.evaluate()
         best_move = (-1, -1)
         return best_score, best_move, count

     # maximizing player
     if maximizingPlayer:
           best_score = float("-inf")
           for move in moves_list:
                new_board = deepcopy(Board)
                new_board.play_legal_move(move[0], move[1], player, opp, flip=True)
                the_score, the_move, count = alphabeta(new_board, False, depth-1, count+1, alpha, beta)
                if (the_score > alpha):
                    alpha = the_score
                    best_move = move
                if beta <= alpha: break

           return alpha, best_move, count
     # minimzing player
     else:
           best_score = float("inf")
           for move in moves_list:
                new_board = deepcopy(Board)
                new_board.play_legal_move(move[0], move[1], player, opp, flip=True)
                the_score, the_move, count = alphabeta(new_board, True, depth-1, count+1, alpha, beta)
                if (the_score < beta):
                    beta = the_score
                    best_move = move
                if beta <= alpha: break

           return beta, best_move, count

1 个回答

5

我觉得现在你已经实现了最小最大算法(minimax),这已经不错了,但你需要加入一个非常重要的优化,叫做α-β剪枝。这个优化只需要对你的代码做一些简单的修改,就能大幅提升运行速度。

编辑:

我注意到你已经使用了α-β剪枝,所以你可以实现negamax(负最大算法),但你认为它不切换的说法是不对的。实际上,它能减少最小最大算法的代码量(我怀疑在速度上不会有显著提升)。这里的核心思想是,一个玩家的得分总是另一个玩家得分的负值,但绝对值是相同的,这样你就可以用公式max(a,b) = -min(-a,-b)来计算。

简单来说就是:

score = -negamax(depth-1,-player)
best = max(score,best)

这些只是用negamax来评估最小最大算法的代码行。

在这里,你不需要交替评估最小值和最大值,因为给最小玩家的分数总是正玩家分数的负值,这样你就可以直接评估最大值来得到正确的分数。

注意:

这在速度上并不是一个显著的优化,但能让代码更简单易读,所以还是值得的。不过不幸的是,你需要删除很多代码才能把你的代码转换成negamax,所以我建议不要这样做。

撰写回答