我正在尝试用换位表实现alpha-beta-min-max修剪增强。我用这个伪代码作为参考:
http://people.csail.mit.edu/plaat/mtdf.html#abmem
function AlphaBetaWithMemory(n : node_type; alpha , beta , d : integer) : integer;
if retrieve(n) == OK then /* Transposition table lookup */
if n.lowerbound >= beta then return n.lowerbound;
if n.upperbound <= alpha then return n.upperbound;
alpha := max(alpha, n.lowerbound);
beta := min(beta, n.upperbound);
if d == 0 then g := evaluate(n); /* leaf node */
else if n == MAXNODE then
g := -INFINITY; a := alpha; /* save original alpha value */
c := firstchild(n);
while (g < beta) and (c != NOCHILD) do
g := max(g, AlphaBetaWithMemory(c, a, beta, d - 1));
a := max(a, g);
c := nextbrother(c);
else /* n is a MINNODE */
g := +INFINITY; b := beta; /* save original beta value */
c := firstchild(n);
while (g > alpha) and (c != NOCHILD) do
g := min(g, AlphaBetaWithMemory(c, alpha, b, d - 1));
b := min(b, g);
c := nextbrother(c);
if g <= alpha then
n.upperbound := g;
store n.upperbound;
if g > alpha and g < beta then
n.lowerbound := g;
n.upperbound := g;
store n.lowerbound, n.upperbound;
if g >= beta then
n.lowerbound := g;
store n.lowerbound;
return g;
这个算法有三个问题:
我相信我应该在保存的每个换位表条目中存储深度(=到叶级的距离),并且仅当entry.depth>=currentdepth(=entry与叶级的距离大于或等于)时才使用entry。这在上面的伪代码中没有显示,这里也没有讨论,我想确保我理解正确。
我想存储每个位置的最佳移动,以便在搜索停止后使用它进行移动排序和提取最佳移动。在pure min max中,很明显哪个移动是最好的,但是当使用alpha beta截止值迭代时哪个移动是最好的?我能假设给定位置的最佳移动是在循环结束时找到的最佳移动吗(有无截止)?
在迭代深化方案中执行此算法时,是否应在每次深度增加之前清除换位表?我想不是,我希望tu使用前一次迭代中的存储位置,但是我不确定信息是否足以进行更深入的搜索(应该是在检查表条目深度时)?
最佳答案
你说得对。entry.depth
存储转置表条目中信息所基于的层数。因此,只有在entry.depth >= remaining_depth
时才能使用这些信息。
逻辑是我们不想使用比“正常”搜索弱的结果。
有时,出于调试目的,条件更改为:
entry.depth == remaining_depth
这避免了一些search instabilities。无论如何,它不能保证没有换位表的搜索结果相同。
并不是总有一个最好的存储方法。
如果搜索失败率很低,就没有“最佳行动”。我们知道的唯一一件事是,任何一个动作都不足以产生大于
alpha
的分数。没有办法猜测哪一步是最好的。因此,您应该在哈希表中存储一个移动,仅用于下限(beta截止,即反驳移动)和精确分数(pv节点)。
不,你不应该这样做。随着迭代的深入,同样的位置会一次又一次地到达,换位表可以加快搜索速度。
您应该清除移动之间的换位表(或者,最好使用一个额外的
entry.age
字段)。