使用内存进行 alpha-beta 搜索何时返回截止值?

dyl*_*unn 5 algorithm chess artificial-intelligence minimax alpha-beta-pruning

我已经使用换位表实现了 alpha beta 搜索。

关于在表中存储截止值,我有正确的想法吗?

具体来说,我在发生表命中时返回截止值的方案是否正确?(同样,存储它们。)我的实现似乎与冲突,但直观上对我来说似乎是正确的。

另外,我的算法从不存储带有 at_most 标志的条目。我应该什么时候存储这些条目?

这是我的(简化的)代码,演示了主要思想:

int ab(board *b, int alpha, int beta, int ply) {
    evaluation *stored = tt_get(b);
    if (entryExists(stored) && stored->depth >= ply) {
        if (stored->type == at_least) { // lower-bound
            if (stored->score >= beta) return beta;
        } else if (stored->type == at_most) { // upper bound
            if (stored->score <= alpha) return alpha;
        } else { // exact
            if (stored->score >= beta) return beta; // respect fail-hard cutoff
            if (stored->score < alpha) return alpha; // alpha cutoff
            return stored->score;
        }
    }   

    if (ply == 0) return quiesce(b, alpha, beta, ply);

    int num_children = 0;
    move chosen_move = no_move;
    move *moves = board_moves(b, &num_children);

    int localbest = NEG_INFINITY;
    for (int i = 0; i < num_children; i++) {
        apply(b, moves[i]);
        int score = -ab(b, -beta, -alpha, ply - 1);
        unapply(b, moves[i]);
        if (score >= beta) {
            tt_put(b, (evaluation){moves[i], score, at_least, ply});
            return beta; // fail-hard
        }
        if (score >= localbest) {
            localbest = score;
            chosen_move = moves[i];
            if (score > alpha) alpha = score;
        }
    }
    tt_put(b, (evaluation){chosen_move, alpha, exact, ply});
    return alpha;
}
Run Code Online (Sandbox Code Playgroud)

man*_*lio 3

我的实现似乎与此冲突

转置表查找的代码对我来说似乎是正确的。大致相当于维基百科上的内容。

// Code on Wikipedia rewritten using your notation / variable names
if (entryExists(stored) && stored->depth >= ply)
{
  if (stored->type == at_least)
    alpha = max(alpha, stored->score);
  else if (stored->type == at_most)
    beta = min(beta, stored->score);
  else if (stored->type == exact)
    return stored->score;

  if (alpha >= beta)
    return stored->score;
}
Run Code Online (Sandbox Code Playgroud)

这相当于(检查if (alpha >= beta)已移至每个节点类型内):

if (entryExists(stored) && stored->depth >= ply)
{
  if (stored->type == at_least)
  {
    alpha = max(alpha, stored->score);
    if (alpha >= beta)  return stored->score;
  }
  else if (stored->type == at_most)
  {
    beta = min(beta, stored->score);
    if (alpha >= beta)  return stored->score;
  }
  else if (stored->type == exact)
    return stored->score;
}
Run Code Online (Sandbox Code Playgroud)

这可以改变:

if (entryExists(stored) && stored->depth >= ply)
{
  if (stored->type == at_least)
  {
    // if (max(alpha, stored->score) >= beta) ...
    if (stored->score >= beta)  return stored->score;
  }
  else if (stored->type == at_most)
  {
    // if (min(beta, stored->score) <= alpha) ...
    if (stored->score <= alpha)  return stored->score;
  }
  else if (stored->type == exact)
    return stored->score;
}
Run Code Online (Sandbox Code Playgroud)

剩下的区别是维基百科使用失败软优化,而您的代码是经典的 alpha-beta 修剪(失败硬)。Fail-soft 是一个小的改进,但不会改变算法的关键点。


我的算法从不存储带有 at_most 标志的条目。我应该什么时候存储这些条目?

exact存储/节点类型的方式存在错误at_most。这里您假设节点始终是类型exact

tt_put(b, (evaluation){chosen_move, alpha, exact, ply});
Run Code Online (Sandbox Code Playgroud)

实际上它可以是一个at_most节点:

if (alpha <= initial_alpha)
{
  // Here we haven't a best move.
  tt_put(b, (evaluation){no_move, initial_alpha, at_most, ply});
}
else
   tt_put(b, (evaluation){chosen_move, alpha, exact, ply});
Run Code Online (Sandbox Code Playgroud)