国际象棋negamax功能

时间:2012-09-09 21:51:14

标签: python chess

嗨!

我正在尝试为我的国际象棋引擎编写一个negamax搜索算法,但我似乎无法让它工作。我使用wikipedias伪代码作为示例,但不知何故它不会产生预期的结果。当我以2的ply运行它时,它会改变我的电路板数据结构,尽管它不应该。功能完成与ply 2一起运行后,所有白色(或黑色的。取决于玩家所称的功能。)棋子从起始位置向前移动2个空格。

我的make和unmake move函数运行正常,因为我使用非递归函数测试它们,搜索最多5层。然后,它完美地工作。我的negamax实现一定有问题。

非常感谢你的帮助!

def negaMax(self, board, rules, ply, player):
        """ Implements a minimax algorithm. """
        if ply == 0:
            return self.positionEvaluation()

        self.max_eval = float('-infinity')

        self.move_list = board.generateMoves(rules, player)
        for self.move in self.move_list:
            board.makeMove(self.move, player)
            self.eval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player))
            board.unmakeMove(self.move, player)

            if self.eval > self.max_eval:
                self.max_eval = self.eval

        return self.max_eval

1 个答案:

答案 0 :(得分:3)

这里的主要问题是我相信使用对象变量而不是局部变量。

self.move是一个对象变量,每次更改它时 - 递归的每个级别都会“看到”更改,这对于递归算法来说通常是一件坏事。

递归算法应该是自包含的,并且如果对调用环境有任何改变则做最小化 - 它使得更容易遍历算法流程。

我在此代码中看到的两个主要问题是:

  1. self.move应该是本地变量(将其声明为move)。当你稍后做:board.unmakeMove(self.move, player) - 我怀疑该板正在撤消一个不同的移动,它在递归树中设置得更深,而不是你想要的移动。使用局部变量将消除这种不良行为。
  2. 递归调用的每个级别都设置为self.max_eval = float('-infinity') - 因此您不断更改它,尽管它可能不是您想要做的。
  3. 解决方案应该是这样的:

    def negaMax(self, board, rules, ply, player):
            """ Implements a minimax algorithm. """
            if ply == 0:
                return self.positionEvaluation()
    
            max_eval = float('-infinity')
    
            move_list = board.generateMoves(rules, player)
            for move in move_list:
                board.makeMove(move, player)
                currentEval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player))
                board.unmakeMove(move, player)
    
                if currentEval > max_eval:
                    max_eval = currentEval 
            return max_eval
    

    我不是100%肯定它确实会解决代码中的所有内容(但它会解决其中的一部分)但我100%肯定避免使用对象变量会使代码更容易理解和调试。