我正在创建一个连接四个AI。我遇到了alpha-beta修剪优化的问题。维基百科说,对节点进行排序,以便我们首先尝试最可能的节点(即最有可能强制执行alpha / beta截断的节点)将在不改变结果的情况下提高性能。这是我的代码没有排序。它似乎工作正常。
def minimax_i(board, start_depth):
"""Return the highest valued move by minimaxing."""
best_value = -100000
best_move = None
alpha = -100000
beta = 100000
moves = board.get_valid_moves()
for move in moves:
value = minimax_r(board.make_move(move), board.nextplayer, alpha, beta, start_depth)
if value > best_value:
best_value = value
best_move = move
if alpha >= beta:
break
return best_move
def minimax_r(board, player, alpha, beta, depth):
result = board.winner()
if result != -1: # If game is finished
if result == 0:
return 0
if result == player:
return 1000 + depth
return -(1000 + depth)
if depth <= 0:
return heuristic(board, player)
moves = board.get_valid_moves()
if board.nextplayer == player: # Maximizing
best_value = -100000
for move in moves:
score = minimax_r(board.make_move(move), player, alpha, beta, depth-1)
best_value = max(best_value, score)
alpha = max(alpha, best_value)
if alpha >= beta:
break
return best_value
else: # Minimizing
best_value = 100000
for move in moves:
score = minimax_r(board.make_move(move), player, alpha, beta, depth-1)
best_value = min(best_value, score)
beta = min(beta, best_value)
if alpha >= beta:
break
return best_value
将moves = board.get_valid_moves()
更改为moves = sorted(board.get_valid_moves(), key = lambda x: abs(board.lastmove[0]-x))
应该使其检查最后一次移动边界的移动,这是一种天真但有希望有用的排序启发式算法。问题是它会更改搜索结果。
我唯一能想到的是,我应该将对子节点中发生的alpha和beta的更改传播回父节点。有什么想法吗?
答案 0 :(得分:0)
无法确定您的问题,但我可以为您提供一些有用的见解。首先,你写道:
我唯一能想到的是,我应该将对子节点中发生的alpha和beta的更改传播回父节点。有什么想法吗?
这是不正确的。 alpha-beta修剪背后的直觉是,如果因为早期节点不会选择它而永远不会到达此分支,则修剪此分支。 Alpha和beta是早期节点找到的最佳移动的边界。传播alpha和beta备份树是没有意义的。如果您仍然不清楚,我建议您在继续之前确保掌握算法。
现在,关于你的问题是什么:你的假设存在轻微的不准确性,但它会产生很大的差异。你写道:
维基百科说,对节点进行排序,以便我们首先尝试最可能的节点(即最有可能强制执行alpha / beta截断的节点),这样可以在不改变结果的情况下提高性能。
这大部分都是正确的,但并非完全如此,尽管维基百科确实这么说。 Alpha-beta修剪不会改变结果的值。这意味着如果常规极小极大显示根据您正在使用的启发式评估函数,移动x值为5,则alpha-beta修剪也将返回该值。但是,如果两个移动具有相同的值,那么这两个移动都不比另一个更好,alpha-beta修剪返回不同的移动是正常的,因为移动顺序的变化可能导致首先看到一个移动。
所以检查一下。这是否会返回同等价值的不同移动,但仍然评估所有移动与minimax具有相同的值?这个是正常的。是否导致实际上不同地评估了移动?这是一个严重的错误。
如果你发现后者是真的,很可能是因为你的移动命令无意中忽略了列表中的移动。另一个可能的原因是算法的实现不正确,但是从你的代码来看似乎没问题。