如何在迭代加深中使用计时器停止alpha-beta

问题描述

我创建了一个带有alpha beta修剪的minimax函数,我称之为迭代加深。问题在于计时器完成后,该功能将继续运行,直到完成计时器用尽之前的深度为止。

我想要的内容:当计时器用尽时,应该退出minimax函数,并且不返回任何值(我保持最佳状态超出minimax,请参见下面的minimax调用代码),或者返回先前计算出的最佳值移动。我只是似乎无法弄清楚如何在minimax函数中实现这一点,我尝试的所有结果都导致它仍然完成了当前的深度。

Minimax函数

def minimax(gamestate,depth,alpha,beta,maximizing_player):

    if depth == 0 or gamestate.is_check_mate or gamestate.is_stale_mate:
        return None,evaluate(gamestate)

    gamestate.is_white_turn = not maximizing_player
    children = gamestate.get_valid_moves()

    best_move = children[0]

    if maximizing_player:
        max_eval = -math.inf
        for child in children:
            board_copy = copy.deepcopy(gamestate)
            board_copy.make_move(child)
            current_eval = ai_minimax(board_copy,depth - 1,False)[1]
            if current_eval > max_eval:
                max_eval = current_eval
                best_move = child
            alpha = max(alpha,current_eval)
            if beta <= alpha:
                break
        return best_move,max_eval

    else:
        min_eval = math.inf
        for child in children:
            board_copy = copy.deepcopy(gamestate)
            board_copy.make_move(child)
            current_eval = ai_minimax(board_copy,True)[1]
            if current_eval < min_eval:
                min_eval = current_eval
                best_move = child
            beta = min(beta,min_eval 

具有迭代加深的函数调用

for depth in range(1,max_search_depth):
    time_start = time.time()
    move,evaluation = minimax(gamestate,maximizing_player)
    time_end = time.time()
    timer = time_end - time_start
    if timer > max_search_time:
        break 

解决方法

我经常使用自定义Timeout类来解决此类问题。

import signal

class TimeoutError(Exception):
    """
    Custom error for Timeout class.
    """

    pass


class Timeout:
    """
    A timeout handler with context manager.
    Based on UNIX signals.
    """

    def __init__(self,seconds=1,error_message="Timeout"):
        self.seconds = seconds
        self.error_message = error_message

    def handle_timeout(self,signum,frame):
        raise TimeoutError(self.error_message)

    def __enter__(self):
        signal.signal(signal.SIGALRM,self.handle_timeout)
        signal.alarm(self.seconds)

    def __exit__(self,type,value,traceback):
        signal.alarm(0)

您可以在with statement内运行递归函数,如下所示:

with Timeout(5):
    try:
        result = minimax(gamestate,depth,alpha,beta,maximizing_player)
    except TimeoutError:
        result = None