问题描述
我创建了一个带有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