我理解杀手启发式背后的想法及其有用的原因。我正在努力的是如何在Alpha-Beta搜索例程中实现它。特别是,如何确保首先尝试兄弟节点的杀手移动?伪代码将会有很大的帮助。
答案 0 :(得分:4)
我将解决实施问题。要获得兄弟节点的杀手移动,请使用类似这样的方案
killerMoves[ply][slot]
其中ply
是距根(不是搜索深度)的距离,而slot
是你想要的杀手数。这确保首先尝试兄弟节点,因为兄弟节点处于同一层。
要在获得β截止时插入杀手移动,您可以将给定合拢的移动向右移动,可能会丢弃旧移动,然后插入新移动。通常,您不会将捕获或散列移动存储为杀手移动,因为它们是通过其他机制进行排序的。
for (int i = killerMoves[ply].Length - 2; i >= 0; i--)
killerMoves[ply][i + 1] = killerMoves[ply][i];
killerMoves[ply][0] = move;
现在,当您执行移动排序时(在迭代移动列表之前),您可以确定移动是否是一个杀手移动:
for (int slot = 0; slot < killerMoves[ply].Length; slot++) {
int killerMove = killerMoves[ply][slot];
for (int i = 0; i < movesCount; i++)
if (moves[i] == killerMove) {
// moves[i] is a killer move so move it up the list
break;
}
}
你不需要为一层或类似的东西清除杀手动作,因为杀手动作很可能是在同一层上出现的一系列类似位置的良好移动。
由于另一个答案提出来了,你可能不需要进行严格的测试,因为杀手启发式在理论上是合理的。你可以试验你使用的杀手动作的数量(2或3是常态)以及它们相对于其他好动作(如捕获)的排序。
答案 1 :(得分:2)
在搜索树的许多部分,杀手移动可能是一个很好的反驳行动。因此,尝试其他职位的杀手动作可能是一个好主意。
每个ply你可能有不同的杀手动作阵列,并且在进入(ply)时清除阵列for(ply + 1),这将给你一个'仅兄弟姐妹'的杀手。我会说'+1'偏移类似于调整参数:尝试清除数组(ply + N)而不是看性能最佳(我猜增加N会改善事情)。
顺便说一句,对引擎性能的评估是一个不同的资源消耗任务:通常引擎试图解决测试套件,或者两个具有不同参数的引擎正在进行匹配(匹配应该足够长,例如100个游戏)他们之间要确定哪个更好。