有没有想过电脑是如何开机的 LocalChess 决定玩什么?它并不神奇,也没有连接到服务器 - 整个对手在您的浏览器选项卡中运行,在您自己的处理器上,使用大约 43 KB 的 JavaScript。

大多数“国际象棋引擎如何工作”的文章都描述了 Stockfish,这是一个带有神经网络和一千行评估的程序。这个描述了一个小型引擎,您实际上可以通过它使用的实数进行端到端推理。下面的所有内容都是已发布代码的作用,而不是简化。

搬家的四个阶段

每次轮到计算机时,引擎都会运行相同的管道:

  1. 生成 该职位的每一次合法变动。
  2. 搜索 向前通过最终的位置,交替进行。
  3. 评价 它到达的安静位置,将他们打成厘兵。
  4. 选择 可以保证获得最佳分数的举动。

有趣的部分是它如何保持第 2 阶段和第 3 阶段足够快,以便在您的移动之间运行而不冻结页面。

第一阶段:产生合法的动作

在选择之前,引擎需要它的选项:每个兵推,骑士跳跃,捕获,升级,en passant和 易位 移动规则允许。这与停止的规则逻辑相同 你 做出非法的举动,所以引擎永远不会作弊——它完全按照你的限制进行游戏。

典型的中局位置有 30-40 步合法步数。这个数字就是为什么提前搜索变得如此昂贵的原因:如果你检查每一个选项,那么在 35 个选项中深入查看 4 个动作,每个选项大约有 150 万个位置。接下来的两节将讨论不要这样做。

第二阶段:评估——将立场转化为数字

引擎得分位置 厘棋子,其中 100 = 一个棋子。底座材质:

Pawn   = 100      Rook  = 500
Knight = 320      Queen = 900
Bishop = 330      King  = not counted

有两个细节值得注意。主教值得 330到骑士的320 — 刻意设计的 10 厘兵边缘反映了主教在空位中的更长触及范围。它足够小,以至于当位置需要时,引擎仍然会用主教交换骑士,但没有其他东西可以区分两个选项,它更愿意保留主教。而且国王根本没有任何物质价值,因为它永远不会被捕获:失去它会被单独处理为将死,得分为 1,000,000,这个数字被选择为使任何材料总数相形见绌,这样任何材料的数量都不会超过配偶。

不过,仅靠材料就可以制造出非常愚蠢的发动机。它很乐意将骑士留在边缘,将国王留在中心,因为这些不需要任何物质成本。因此,除了材质之外,引擎还添加了 一块方桌 — 每件网格包含 64 个小奖励和惩罚,编码了位置常识:

  • 骑士 角落得分为−50,中心四个方块得分为+20 — 70 分

挥杆,多半是棋子。边缘上的马到达四个方格;中间的一个达到了八个,桌子上的价格正是这个数字。

  • 棋子 随着他们的进步变得更有价值:占领d4或e4+25,上升到+50

整个七阶,距离晋级仅一步之遥。 d2 和 e2 方格带有 −20 处罚,这是引擎被告知发挥其中心棋子而不是把它们留在家里的方式。

  • 鲁克斯 沿着第七个等级获得+10,编码了旧原则,即车在

第七个的价值比其材料所暗示的要高。

  • 国王 b1 和 g1 上获得+30——它落在之后的方格上

易位 - 对于在棋盘上徘徊的惩罚高达 -50。这就是为什么引擎在没有被告知的情况下就提前城堡了。

最后一张表中有一个诚实的限制。发动机采用 残局和中局的国王桌相同,没有相位检测。但在残局中,建议会颠倒过来:在皇后离开的情况下,国王是一个战斗棋子,应该向中心前进,这正是 d5 的 -50 惩罚所阻止的。因此,引擎在应该激活它之后很长时间仍将其国王隐藏起来。如果你想打败Hard, 残局中的国王活动 是找到它看不到的边缘的最可靠的地方。

结果是一个数字,如果移动的一方更好,则为正。这个数字正是推动 评价栏 在黑板旁边。

将死、相持、三重重复和平局在任何一次运行之前都是特殊情况:交手返回极限分数,每种平局都返回精确的 0。

第三阶段:使用 negamax 和 alpha-beta 进行搜索

只评估当前位置是短视的——它会抓住一个空闲的棋子,并在下一步行动中进入伙伴。所以引擎会使用 负加麦克斯,一种紧凑形式的极小极大,利用了一种简洁的对称性:对我来说得分为+3的位置对你来说得分为-3。因此,您不必编写单独的“最大化”和“最小化”逻辑,而是编写一个函数并在每一级翻转符号。

就其本身而言,这仍然意味着访问每个分支机构。引擎避免了其中的大多数 α-β剪枝,它跟踪双方已经可以施加的最佳分数。当一个分支被证明比已经保证的东西更糟糕时,该分支的其余部分就无关紧要了——对手永远不会允许它——所以它被放弃而不进行搜索。在实践中,这会在不改变所选择的移动的情况下极大地砍伐树木:答案与搜索所有内容相同,只是速度要快得多。

静止:不停止中途交易

这里有一个经典的陷阱,叫做 地平线效应。如果搜索正好停在第四步,而第四步恰好是 你的皇后捕获了一个被防御的棋子,引擎看到“+1 pawn”并称该位置良好 - 从未注意到在第五步中皇后被重新捕获。

解决办法是 静止搜索。当主要搜索超出深度时,它不会停止;它继续前进,但看着 仅捕获,直到到达一个没有任何东西悬挂的安静位置。这就是为什么引擎不会在其搜索窗口的边缘悬挂碎片,并且这是最能区分感觉有能力的机器人和感觉随机的机器人的单一功能。

迭代深化和时间预算

发动机不会直接跳到最大深度。它搜索深度 1,然后搜索深度 2,然后搜索 3,保留迄今为止找到的最佳移动。这听起来很浪费——你每次都重做工作——但浅层传递比深层传递便宜得多,因此开销很小,而且它买了一些有价值的东西: 引擎始终准备好合法、合理的移动.

这很重要,因为每一步行动都有一个截止日期。如果搜索爆炸 - 具有长捕获链的战术位置是常见的原因 - 截止时间触发,部分搜索被丢弃,并且引擎从最后完成的深度开始执行最佳移动。页面永远不会冻结等待机器人,这就是截止日期存在的全部原因。

简单、中等和困难之间实际上有什么变化

这是大多数网站都模糊的地方。确切的设置:

|水平|搜索深度|每次移动的时间预算|随机移动机会| | ---| ---| ---| ---| | 简单 | 2层| 250 毫秒 | 35% | | 中等 | 3层| 500 毫秒 |无 | | 硬 | 4层| 1100 毫秒 |无 |

“层”是一侧的移动,因此 Hard 的深度为 4 意味着它会看到自己的两个移动和你的两个移动 - 加上静止点之后的捕获链。

Easy 专栏值得深入探讨。 35% 的情况下,Easy 完全忽略搜索并随机下合法棋步。 这不是一个弱化的评估,也不是一个肤浅的计划;大约三分之二的情况下,这是真正的好棋,其余的情况下就像抛硬币一样。对于初学者来说,这是一个经过深思熟虑的设计选择:这意味着 Easy 将以浅引擎永远不会的方式悬挂棋子,为新玩家提供真正的机会来惩罚错误。

这还意味着一件值得了解的事情: 如果Easy演奏出令人费解的东西,那么背后可能根本就没有任何想法。 不要花五分钟寻找计划。对抗中级和困难级时,每一步棋都是真实搜索的结果,因此看起来奇怪的棋步通常确实有道理。

为什么它会这样播放

了解其内部结构告诉你如何玩它,这才是真正的重点:

  • 它不会演奏任何书本上的动作。 代码中有一个小开口表,但是它存在

只为了 姓名 你所下的开局,并在分析中将早期动作标记为“书”——引擎在选择时从不参考它。从第一步开始的每一步都是从头开始搜索的,因此它会发挥合理但不拘泥于书本的开局,并且几乎立即离开理论。

  • 这是一个比战略家更好的战术家。 四层加静止捕获最短

战术,但十步见效的计划,它却完全看不到。封闭、缓慢的头寸是它最薄弱的地方。

  • 它不会陷入深深的陷阱,但会陷入长期的困境。 如果你的想法

需要三步才能起作用,它就会看到它。如果需要十二个,那就不会了。

对此有更全面的战略处理 如何与电脑下棋.

相同的引擎审查您的游戏

当你击中 分析比赛 一场比赛结束后,同样的代码再次运行——而不是一个不同的、更强的分析器。对于每个位置,它都会搜索两次:一次搜索您实际下的棋步,一次搜索它能找到的最佳棋步,两次搜索的深度相同,并且都使用叶子的静止状态。这两个分数之间的差异就是您在该动作中损失的 centipawn。

因为两个搜索都运行到相同的实际深度,所以这些数字在内部是一致的——您正在将同类进行比较。它们不是鳕鱼干级别的绝对判断,而是用于发现 哪里 比赛结束后,他们是可靠的。如果搜索在截止日期前被缩短,则部分结果将被丢弃而不是报告,因此分析会降级到较浅但仍然准确的深度,而不是悄悄地给您带来噪音。

自己尝试一下

对“简单”和“困难”玩相同的开局,观察回复如何尖锐。然后运行 分析比赛 并比较评估曲线——简单游戏将显示随机移动骰子不足的突然悬崖,而困难游戏显示更平滑的路线,损失集中在真正的战术时刻。

所有这些都在您的设备上运行,这也是为什么它 在没有互联网连接的情况下继续工作.