国际象棋引擎走出开局库后返回None引发AttributeError问题排查
国际象棋引擎走出开局库后返回None导致AttributeError问题排查
问题概述
国际象棋引擎使用polyglot开局库时运行正常,但走出开局库后,调用iterativeDeepening函数返回None,执行board.push(result)时触发AttributeError,报错显示'NoneType' object has no attribute 'from_square'。
完整代码
import random import chess import chess.polyglot import time from evaluate import * max_depth = 18 move_points = [] def nextMove(board, color)->(chess.Move): try: best_move = chess.polyglot.MemoryMappedReader("books/human.bin").weighted_choice(board).move return best_move except IndexError: best_move = iterativeDeepening(board, color,5) return best_move def iterativeDeepening(board, color, max_time): start = time.time() for move in board.legal_moves: move_points.append((0,move)) best_move = None for i in range(1, max_depth + 1): points,best_move = minimax(i, board, float('inf'), -float('inf'), color==board.turn,None, color, ) if time.time() - start >= max_time: break move_points.clear() return best_move def minimax(depth, board, alpha, beta, maxPlayer, curmove, ai_color): if depth == 0: for move in board.legal_moves: if move == curmove: points = quiescence(1, board, alpha, beta, maxPlayer) quiescence(1, board, alpha, beta, maxPlayer) eval_val = eval(board) if (eval_val == float('inf') or eval_val == -float('inf')) and board.turn == ai_color: print("mate you lose") exit(0) if (eval_val == float('inf') or eval_val == -float('inf')) and board.turn != ai_color: print("mate you win") exit(0) if eval_val == "draw": print("draw") exit(0) return -eval_val, curmove if maxPlayer: maxEval = -float('inf') best_move = curmove for move in board.legal_moves: board.push(move) evalu, _ = minimax(depth - 1, board, alpha, beta, False, move, ai_color) board.pop() if evalu > maxEval: maxEval = evalu best_move = move alpha = max(alpha, evalu) if beta <= alpha: break return maxEval, best_move else: minEval = float('inf') best_move = curmove for move in board.legal_moves: board.push(move) evalu,_ = minimax(depth - 1, board, alpha, beta, True, move, ai_color) board.pop() if evalu < minEval: minEval = evalu best_move = move beta = min(beta, evalu) if beta <= alpha: break return minEval, best_move def quiescence(depth, board, alpha, beta, maximizingPlayer): if depth == 0: return -eval(board) if maximizingPlayer: maxEval = -float('inf') has_capture = False for move in board.legal_moves: if board.is_capture(move): has_capture = True board.push(move) evalu = quiescence(depth - 1, board, alpha, beta, False) board.pop() maxEval = max(maxEval, evalu) alpha = max(alpha, evalu) if beta <= alpha: break if not has_capture: return -eval(board) return maxEval else: minEval = float('inf') has_capture = False for move in board.legal_moves: if board.is_capture(move): has_capture = True board.push(move) evalu = quiescence(depth - 1, board, alpha, beta, True) board.pop() minEval = min(minEval, evalu) beta = min(beta, evalu) if beta <= alpha: break if not has_capture: return -eval(board) return minEval
报错栈
Traceback (most recent call last): File "/Users/user/PycharmProjects/chess bot/main.py", line 21, in <module> board.push(result) File "/Users/user/PycharmProjects/chess bot/venv/lib/python3.9/site-packages/chess/__init__.py", line 2224, in push move = self._to_chess960(move) File "/Users/user/PycharmProjects/chess bot/venv/lib/python3.9/site-packages/chess/__init__.py", line 3664, in _to_chess960 if move.from_square == E1 and self.kings & BB_E1: AttributeError: 'NoneType' object has no attribute 'from_square' AI move: None
问题定位
iterativeDeepening初始best_move为None:若循环未执行(比如初始时间直接超过max_time),或minimax始终返回None作为走法,最终会返回None。minimax未记录最佳走法:初始调用时curmove传入None,遍历合法走法后未更新curmove为最优走法,始终返回初始的None。- 逻辑判断错误:
eval(board) == (float('inf') or -float('inf'))写法无效,实际仅会判断eval(board) == float('inf');quiescence中if(maxEval==None)判断错误,maxEval初始为-float('inf'),永远不会等于None。 - 参数未定义:
iterativeDeepening中调用minimax时使用ai_color==board.turn,但ai_color未定义,应改为传入的color参数。
修复方案
minimax新增最佳走法记录:在maxPlayer和minPlayer分支中,遍历合法走法时,同步更新best_move为当前最优走法,避免返回None。- 修正
iterativeDeepening调用参数:将ai_color==board.turn改为color == board.turn,确保maxPlayer参数正确。 - 修复
eval判断逻辑:将合并判断拆分为eval_val == float('inf') or eval_val == -float('inf'),确保逻辑有效。 - 修正
quiescence评估逻辑:通过has_capture标记是否存在捕获走法,无捕获走法时返回静态评估值,避免返回错误的初始值。
同时建议检查evaluate.py中的eval函数,确保返回值类型统一(避免同时返回数值和字符串"draw",导致类型判断错误)。
内容的提问来源于stack exchange,提问作者mishari alhussain
相关产品推荐
相关产品推荐

