国际象棋引擎中 "make move" 和 "undo move" 有什么意义?

What's the point of "make move" and "undo move" in chessengines?

我想尝试大规模并行国际象棋计算。从我在 wiki 和一些引擎的源代码中看到和理解的是,在大多数(所有?)最小-最大(negamax,alpha-beta,...)算法的实现中,有一个内部位置会更新每个新分支然后在收到该分支的评估后撤消。

与仅生成新的位置对象并将其传递给下一个分支相比,该技术有哪些优势? 这是我在以前的引擎中所做的,我相信这种方法在并行性方面更胜一筹。

您的问题的答案在很大程度上取决于几个因素,例如您如何存储棋盘,以及您的 make/unmake 移动功能是什么样的。我敢肯定有一些方法可以更适合您的方法来存储棋盘,而且历史上确实有一些顶级国际象棋引擎(特别是狡猾的)曾经使用过该方法,但是您说现代引擎不再是正确的那样做。这是关于这一点的讨论 link: http://www.talkchess.com/forum/viewtopic.php?t=50805

如果你想了解这是为什么,那么你必须了解今天的引擎是如何代表董事会的。标准实现围绕位板,每个位置需要 12-64 位整数,此外还需要结合使用冗余邮箱(非计算机国际象棋术语中的数组)。复制所有通常比 good makeMove/unMakeMove 函数更昂贵。

我还想指出混合方法也很常见。通常 make 和 unmake 用于棋盘本身,其他信息如 en passant squares 和 castle rights 会按照您的建议进行复制和更改。

有趣的是,对于 < ~300 字节的棋盘表示,每次移动(在现代 x86 上)都复制棋盘比移动和取消移动更便宜。

正如您所说,从编程的角度来看,每次移动复制棋盘的不变属性,包括并行化,非常有吸引力。

我的董事会代表是 208 字节。用 g++ 7.4.0 编译的 C++。

经验表明复制棋盘比移动快 20% make/unmake。我假设代码使用 32/64 字节宽的 AVX 指令进行复制。理论上每个周期可以复制 32/64 字节。

只为你:https://github.com/rolandpj1968/oom-skaak/tree/init-impl-legal-move-gen-move-do-undo-2