我一直在使用negamax来玩连接四。我注意到的事情是,如果我添加alpha-beta,它有时会产生“错误”的结果,就像在做出失败的举动时,我不相信它应该与我正在搜索的深度。如果我删除alpha-beta,它会播放它应该如何播放。 alpha-beta能否切断一些实际可行的分支(特别是当深度有限时)?以下是代码:
int negamax(const GameState& state, int depth, int alpha, int beta, int color)
{
//depth end reached? or we actually hit a win/lose condition?
if (depth == 0 || state.points != 0)
{
return color*state.points;
}
//get successors and optimize the ordering/trim maybe too
std::vector<GameState> childStates;
state.generate_successors(childStates);
state.order_successors(childStates);
//no possible moves - then it's a terminal state
if (childStates.empty())
{
return color*state.points;
}
int bestValue = -extremePoints;
int v;
for (GameState& child : childStates)
{
v = -negamax(child, depth - 1, -beta, -alpha, -color);
bestValue = std::max(bestValue, v);
alpha = std::max(alpha, v);
if (alpha >= beta)
break;
}
return bestValue;
}
答案 0 :(得分:2)
alpha-beta能否切断一些实际可行的分支(特别是当深度有限时)?
Alpha-Beta算法返回与Minimax相同的结果(根节点和游戏线的评估),但(经常)更快地修剪掉不会影响最终决策的分支(你可以阅读H. Fuller撰写的 Analysis of the alpha-beta pruning algorithm by Samuel 中的证明 - 1973年。
您正在使用 Negamax Alpha-Beta修剪,但它只是简化算法实现的一种变体。
fail-soft 噱头也不会改变这种情况。
当然,浅深度搜索可以选择不好的动作,但同样适用于Minimax。
所以它必须是一个实现错误。
显示的代码似乎对我而言。你应该检查:
在根节点上调用negamax的方式。它应该是这样的:
negamax(rootState, depth, −extremePoints, +extremePoints, color)
alpha
/ beta
是可能的最低值和最高值。
如果您使用alpha
/ beta
的不同初始值(例如aspiration windows)并且真实分数在初始窗口之外,则需要重新搜索。
如何收集/存储/管理/传播主要变体的移动(缺少相关代码)。像PV表这样的技术与bestValue
的变化相关联。如果这是问题,你应该得到相同的位置分数(相对于Minimax),但是不同的最佳动作。
答案 1 :(得分:0)
问题是如何在根节点初始化alpha和beta。我有一个类似的错误,因为我将它们设置为std :: numeric_limits :: min()和std :: numeric_limits :: max(),并在将alpha参数传递给另一个递归调用negamax(... -a_beta, - a_alpha ...)我通过添加一个减号运算符来否定最小int值,因为最小int值的数学否定超出了int的范围(-214748364 8 vs 214748364 <强> 7 强>)。
但是,如果将alpha初始化为不同的值(例如std :: numeric_limits :: min()+ 1),则不是这种情况。