中国象棋计算机博弈发展史研究报告

系统梳理中国象棋计算机博弈从 1980 年代到 2026 年的技术演进、代表引擎与社区生态。 索引C:版本索引 → 第五章 置换表与哈希技术

☰ 目录

索引C:版本索引

将族 - 1989年ICGA夺冠, 1992年DOS发布 棋隐 - 1997年发布 象棋奇兵 - 2005年ICGA夺冠 棋天大圣 - 2006年ICGA夺冠, 2006年CCMC夺冠 象棋旋风 - 2005年首版, 2008年CCMC夺冠 倚天象棋 - 2008年ICGA夺冠 象棋名手 - 2009年CCMC夺冠, 2010-2014年统治时期 佳佳象棋 - 2009年发布 GGzero - 佳佳象棋的RL分支 小虫象棋 - 2013年ICGA夺冠 皮卡鱼 - 2022年GitHub发布 皮卡鱼2022-10-22版 - 残局修复 皮卡鱼2022-12-26版 - 60步规则/WDL引入 皮卡鱼2023版 - 多项小版本优化 皮卡鱼2024-08-31版 - ATT++架构 皮卡鱼2025-06-23版 - AVX512优化 Orange引擎 - 2024年发布


文档结束

本报告将持续更新。最新版本可在以下地址获取:[待定]

报告日期:2026年7月

第七卷 中国象棋引擎核心技术深度解析

第一章 局面表示技术的演进

1.1 数组表示法

最早的中国象棋引擎(将族、棋隐、早期ElephantEye等)使用10x9的二维数组来表示棋盘。每个数组元素存储一个整数,表示该位置上的棋子类型和颜色。

典型的数组表示编码方式:

  • 0:空位
  • 正数(1-7):红方棋子(帅、士、象、马、车、炮、兵)
  • 负数(-1到-7):黑方棋子(将、士、象、马、车、炮、卒)

数组表示的优点:直观易懂、实现简单、调试方便。缺点:效率低、缓存不友好、并行性能差。

1.2 位棋盘(Bitboard)表示法

现代引擎(如皮卡鱼)使用位棋盘(Bitboard)表示法。位棋盘使用多个64位整数来表示棋盘状态。每个位(bit)表示棋盘上的一个交叉点。

中国象棋棋盘有90个交叉点,14种棋子(7种红方+7种黑方)各使用一个64位位棋盘。位棋盘的第0位表示棋盘的左上角,第9位表示左下角,第81位表示右上角。

位棋盘的优势:

  1. 着法生成速度快——通过预计算和位运算
  2. 内存访问高效——数据结构紧凑,缓存友好
  3. 并行性好——位运算天然支持并行执行
  4. 增量更新容易——通过AND/OR/XOR对位棋盘进行位操作

位棋盘的挑战:调试困难(位棋盘的值是二进制整数,不直观);中国象棋棋盘尺寸与64位整数不完全适配(90位 vs 64位)。

第二章 着法生成器(Move Generator)的深度解析

2.1 中国象棋棋子的走法规则

中国象棋7种棋子的走法规则各不相同:

帅/将(King):在九宫格内(行0-2或7-9,列3-5)移动一格(上下左右),不能与对方帅/将在同一直线上无棋子相隔(将帅照面)。

士/仕(Advisor):在九宫格内沿斜线移动一格,只能在九宫格的5个交叉点上移动。

象/相(Bishop):沿斜线走田字(移动2格),有塞象眼的制约,不能过河。

马(Knight):走日字(走2格+1格的组合),有蹩马腿的制约。

车(Rook):沿直线(横或竖)移动任意步数,不能跳过其他棋子。

炮(Cannon):不吃的走法沿直线移动任意步数,不能跳过其他棋子;吃子的走法沿直线移动,跨过一个棋子(炮架)后吃掉遇到的第一个对方棋子。

兵/卒(Pawn):未过河只能向前走一格;过河后可以向前或横向走一格,不能后退。

2.2 着法生成伪代码

中国象棋各棋子的着法生成逻辑:

车的着法生成:对每个方向(上下左右),从当前位置沿方向逐格枚举。格子为空时加入非吃着法并继续;格子为对方棋子时加入吃子着法并停止;格子为己方棋子时停止。格子超出棋盘边界时停止。

炮的着法生成:对每个方向沿方向逐格枚举。使用炮架计数器:计数器为0时,空格加入非吃着法,有棋子则计数器设为1;计数器为1时,对方棋子加入吃子着法并停止,己方棋子停止,空格继续。

马的着法生成:对马的8个目标方向,计算目标位置和绊脚位置。绊脚位置有棋子(蹩马腿)则跳过;目标位置为己方棋子跳过;对方棋子加入吃子着法;空格加入非吃着法。

兵的着法生成:确定前进方向,目标为空或对方棋子时加入着法。兵已过河时,左右方向同规则。

2.3 吃子着法的优先生成机制

在PVS搜索中,吃子着法的生成顺序对搜索效率有重要影响。引擎按照以下优先级:

  1. 置换表最佳着法(如果存在于置换表中)
  2. 吃子胜算着法(SEE评估为正的吃子着法)
  3. 赢子吃子着法(用低价值吃子吃掉高价值子)
  4. 同级吃子着法(用同价值子吃掉同价值子)
  5. 输子吃子着法(用高价值子吃掉低价值子)
  6. 非吃子着法(先杀手着法、历史启发着法,后其他着法)

第三章 评估函数的深度剖析

3.1 手工评估函数的设计

中国象棋引擎的手工评估函数是一系列位置特征的线性组合。典型的评估函数包含:子力价值评估、位置价值评估、棋子活动性评估、将帅安全性评估、局面结构评估、棋子协调性评估、战术调整值。

子力价值评估中,不同棋子的基础价值如下:

  • 帅/将:10000(不可量化价值)
  • 车:600
  • 马:270
  • 炮:285
  • 士/象:120
  • 兵:30-150(随局面阶段变化)

位置价值表是每个棋子在棋盘上每个位置的预设价值。例如,红方兵的位置价值:在己方阵地低分(兵尚未过河),在过河后位置高分,在中路(将帅附近)特别高分。

棋子活动性评估包括马的可走方向数、车的可控制线数、炮的炮架数量和质量等。

将帅安全性评估包括保护将帅的士象数量、将帅周围的控制空间、将帅是否暴露在对方棋子攻击下等。

局面结构评估包括士象完整性、兵的阵型、河界和九宫的控制程度等。

3.2 评估函数的调优过程

手工评估函数的调优是一个系统性的工程:

基础调优:根据已知象棋理论和经验设定基础参数,运行引擎自战多局收集评估偏差,根据偏差调整参数。

局面类型调优:针对特定局面类型(开局、中局、残局、优势、劣势)分别收集测试数据,分析各类型下的评估偏差,调整对应类型下的参数。

精细调优:使用Fishtest或类似统计测试框架进行大规模测试,每次调整一个参数观察ELO变化,只保留ELO提升显著的调整,重复直到参数达到局部最优。

3.3 手工评估函数的体系结构

手工评估函数具有层级结构:

第一层(静态评估):子力价值、位置价值、棋子活动性。

第二层(动态评估):攻击与防守关系、威胁检测、战术组合。

第三层(局面理解):局面阶段性判断、子力交换策略评估、将杀威胁评估。

第四层(规则约束):将帅照面检测、长将长捉检测、困毙检测。

3.4 NNUE评估网络的结构

NNUE评估网络的结构如下:

输入层使用稀疏的HalfKP特征集。输入向量维度约为40,000(中国象棋适配版本)。特征为(己方将帅位置,对方棋子类型+位置),利用棋盘对称性减少特征数量。

隐藏层为1-2层全连接网络。第一层宽度通常为512或1024个神经元,激活函数为Clipped ReLU(裁剪到0-127范围)。第二层(如果存在)宽度通常为32或64个神经元。输出层为一个神经元,输出局面评估值(以百分之一兵为单位)。

NNUE的增量更新特性:每次走棋后,只需要更新与移动棋子相关的输入特征(通常是几个到几十个特征),而不需要重新计算整个网络。这种增量更新的计算复杂度为O(特征变更数 x 隐藏层宽度),远低于O(输入维度 x 隐藏层宽度)。

3.5 评估函数从手工到NNUE的变迁

中国象棋引擎的评估函数经历了从手工到NNUE的根本性变迁:

传统手工评估时代(1989-2021):

  • 评估函数由开发者手动设计和调整
  • 特征数量有限(几十到几百个)
  • 调优依赖开发者经验和对棋理的理解
  • 评估精度有限,但搜索效率高

NNUE评估时代(2022-至今):

  • 评估函数由神经网络自动学习
  • 特征数量巨大(数万个输入特征)
  • 调优依赖训练数据质量和网络结构设计
  • 评估精度显著提高,但推理计算量增加

NNUE对手工评估的优势:

  1. 评估精度更高——NNUE可以发现手工评估难以编码的细微模式
  2. 自动学习——不需要手动设计特征和权重
  3. 持续改进——只要有更好的训练数据,评估精度就能提升
  4. 通用性强——同一网络结构可以适配不同的规则和局面类型

NNUE对手工评估的劣势:

  1. 计算量较大——神经网络推理比线性组合慢
  2. 训练依赖数据——需要大规模高质量的训练数据
  3. 解释性差——难以理解NNUE为何做出特定的评估
  4. 特定模型——不同局面类型可能需要不同的模型

第四章 搜索算法的深度解析

4.1 从Minimax到Alpha-Beta

Minimax搜索是计算机博弈的理论基石。其基本思想是:在博弈树中,每一层代表一个玩家的走棋决策,假设双方都选择对自己最有利的走法。己方(MAX)选择评估值最大的走法,对方(MIN)选择评估值最小的走法。

Minimax的形式化定义:

Minimax(s) = 
  - 如果s是终局局面:返回评估值
  - 如果轮到MAX走棋:max(Minimax(s') for s' in s的所有后继局面)
  - 如果轮到MIN走棋:min(Minimax(s') for s' in s的所有后继局面)

Alpha-Beta剪枝是对Minimax的优化。它维护两个值:

  • alpha:MAX玩家当前最佳保证值(下限)
  • beta:MIN玩家当前最佳保证值(上限)

当一个分支的搜索返回值超出了[alpha, beta]区间时,该分支可以被剪枝(因为不会影响最终的决策结果)。

Alpha-Beta的理想复杂度为O(b^(d/2)),其中b是分支因子(中国象棋约40),d是搜索深度。这意味着在同等时间内,Alpha-Beta可以搜索约两倍深度的局面。

4.2 PVS(主变搜索)的引入

PVS(Principal Variation Search)是Alpha-Beta的高效变体。其核心思想是:假设搜索找到的第一个走法(主变)就是最佳走法,然后使用零窗口(null-window)验证其他分支是否比主变更优。

零窗口搜索的关键:在搜索非主变分支时,使用(alpha, alpha+1)的窗口。如果搜索结果大于alpha(即窗口被突破),说明该分支可能比主变更优,此时使用完全窗口(alpha, beta)重新搜索。

PVS在中国象棋引擎中的实际应用:PVS将搜索效率提高了约10-20%。在分支因子高的中国象棋中,效果尤其显著。

4.3 迭代加深的实践

迭代加深搜索(IDS)是中国象棋引擎的标准搜索策略。其基本流程是从depth=1开始逐层增加搜索深度。

迭代加深的优势:

  1. 时间可控:可以在任何时刻返回最佳着法
  2. 置换表预热:浅层搜索结果可以被深层搜索利用
  3. 搜索稳定性:避免深层搜索的剧烈波动
  4. 着法排序改善:浅层找到的主变为深层搜索提供顺序参考

迭代加深的成本:每次加深需要重新搜索整棵树。但在实际中,由于着法排序的改善和置换表的预热,迭代加深的总成本只比直接最深搜索多约5-15%。

4.4 主要剪枝技术

空着裁剪(Null Move Pruning):假设让对方连续走两步,己方仍然不处于劣势,则当前局面不值得深入搜索。空着裁剪在中国象棋中的使用需要设置安全阈值(R值,通常为2-3层),并避免在危急局面下使用。

LMR(Late Move Reductions):对排序靠后的着法减少搜索深度。因为排序靠后的着法质量较低,不值得全面搜索。LMR的缩减量根据搜索深度、着法类型(吃子/非吃子)和局面类型(是否被将军)动态调整。

SEE(Static Exchange Evaluation):评估吃子交换序列的净得失。SEE在中国象棋中的适配包括吃子价值顺序、炮的跳吃处理、以及将帅不能暴露在将军下的规则约束。

Futility裁剪:在浅层深度(通常是最后几层),如果局面优势或劣势足够大,直接结束搜索。

Razoring:类似于Futility,但在更深的层面上使用。

这些剪枝技术综合使用,中国象棋引擎的搜索效率比基础Alpha-Beta提高了数百倍。

第五章 置换表与哈希技术

5.1 Zobrist哈希的增量更新

Zobrist哈希是中国象棋引擎中最广泛使用的局面哈希技术。它的增量更新特性使得每次走棋后更新哈希值的计算复杂度为O(1)。

增量更新的过程:

  1. 从哈希值中异或掉移动棋子在原位置的随机数
  2. 如果吃子,异或掉被吃棋子在原位置的随机数
  3. 异或上移动棋子在新位置的随机数
  4. 异或上走权标志(表示轮到对方走棋)
  5. 如果将帅照面状态改变,更新照面标志

增量更新的高效性使得引擎可以在每次递归搜索调用中快速更新哈希值。

5.2 置换表的管理策略

置换表的大小和替换策略对搜索引擎性能有直接影响。

条目结构:每个条目包含哈希值签名、搜索深度、节点类型(精确值/Alpha上限/Beta下限)、最佳走法和评估值。

替换策略:

  1. 深度优先替换:保留搜索深度更大的条目(即使它是旧的)
  2. Always Replace:总是用新条目替换旧条目
  3. 混合策略:考虑深度和年龄的加权组合

皮卡鱼使用深度优先的替换策略,因为深度更大的条目提供的信息价值更高。

哈希冲突处理:引擎通常使用32位或64位签名来检测冲突。较大的签名空间可以减少冲突概率,但增加条目大小。