我有一个带有 alpha-beta 修剪的普通 Negamax 算法,它是通过迭代加深 (ID) 启动的。我认为要真正使用 ID,我将从深度 1 计算的有效移动保存在表格中,所以下次我去深度 2 并且相同的原始位置到达时,我可以从表格中获取有效移动来节省时间. 但是,我发现这个想法并没有真正节省任何时间,这让我想到:
- 我从未见过有人这样做,出于某种原因不值得吗?
- 我的实现是错误的?
- 我对 Negamax 的工作方式感到困惑,也许这首先是不可能做到的?
这是原始的迭代调用,以及 Negamax 函数本身的片段:
self.valid_moves_history = []
for depth in range(1, s.max_search_depth):
move, evaluation = self.negamax(gamestate, depth, -math.inf, math.inf, s.start_color)
# ----------------------------------------------------------------------------
def negamax(self, gamestate, depth, alpha, beta, color):
if self.zobrist_key in self.valid_moves_history:
children = self.valid_moves_history[self.zobrist_key]
else:
children = gamestate.get_valid_moves()
self.valid_moves_history[key] = children
if depth == 0 or gamestate.is_check_mate or gamestate.is_stale_mate:
return None, e.evaluate(gamestate, depth) * color
# Negamax loop
max_eval = -math.inf
for child in reversed(children):
gamestate.make_move(child[0], child[1])
score = -self.negamax(gamestate, depth - 1, -beta, -alpha, -color)[1]
gamestate.unmake_move()
if score > max_eval:
max_eval = score
best_move = child
alpha = max(alpha, max_eval)
if beta <= alpha:
break
我的完整程序中最耗时的任务是这样分布的(占游戏总运行时间的百分比):
- 计算有效动作:60%
- 评估函数(目前中等复杂度):25%
- Negamax 本身具有查找、表格保存等功能:5%
- 做出/取消动作:4%
计算移动时间这么高是否正常/合理?这是我首先考虑将有效动作保存在列表中的主要原因。
或者有人可以解释为什么这是一个好/坏的主意,我应该怎么做?感谢您的任何意见。