You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

国际象棋引擎走出开局库后返回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

问题定位

  1. iterativeDeepening初始best_move为None:若循环未执行(比如初始时间直接超过max_time),或minimax始终返回None作为走法,最终会返回None。
  2. minimax未记录最佳走法:初始调用时curmove传入None,遍历合法走法后未更新curmove为最优走法,始终返回初始的None。
  3. 逻辑判断错误:eval(board) == (float('inf') or -float('inf'))写法无效,实际仅会判断eval(board) == float('inf');quiescence中if(maxEval==None)判断错误,maxEval初始为-float('inf'),永远不会等于None。
  4. 参数未定义:iterativeDeepening中调用minimax时使用ai_color==board.turn,但ai_color未定义,应改为传入的color参数。

修复方案

  1. minimax新增最佳走法记录:在maxPlayer和minPlayer分支中,遍历合法走法时,同步更新best_move为当前最优走法,避免返回None。
  2. 修正iterativeDeepening调用参数:将ai_color==board.turn改为color == board.turn,确保maxPlayer参数正确。
  3. 修复eval判断逻辑:将合并判断拆分为eval_val == float('inf') or eval_val == -float('inf'),确保逻辑有效。
  4. 修正quiescence评估逻辑:通过has_capture标记是否存在捕获走法,无捕获走法时返回静态评估值,避免返回错误的初始值。

同时建议检查evaluate.py中的eval函数,确保返回值类型统一(避免同时返回数值和字符串"draw",导致类型判断错误)。

内容的提问来源于stack exchange,提问作者mishari alhussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:25:00