ChessAI
高性能中国象棋(Xiangqi)AI 引擎,基于 u128 位棋盘(bitboard)的纯 Rust 实现。
特性
- 位棋盘表示:单个
u128覆盖 10×9 的中国象棋棋盘,所有走法生成均为位运算。 - Magic Bitboard 攻击表:车、炮的快速查表攻击生成;马、象、兵、士、将采用预生成表。
- Alpha-Beta 搜索:迭代加深 + 换位表(Zobrist 键)+ 空着裁剪 + PVS + 静态搜索(QS)。
- 走法排序:杀手启发、历史启发、反制走法、MVV-LVA、SEE 裁剪。
- Lazy SMP 并行:多线程共享换位表,配合 depth-skip 模式分散搜索。
- 开局库:内嵌
assets/BOOK.DAT,支持走法镜像。 - FEN & ICCS:完整的 FEN 解析/生成,ICCS 坐标(
b2-e2或b2e2)双向转换。 - 构建器 API:
Engine::builder().hash_size(mb).threads(n).build(),零配置即可运行。
安装
[]
= "1"
快速开始
use Duration;
use ;
let mut engine = builder
.hash_size // 换位表 128 MB
.threads // Lazy SMP 4 线程
.build;
let info = engine.search;
if let Some = info.best_move
从任意 FEN 开始
use Engine;
let mut engine = builder.build;
engine.set_fen?;
println!;
println!;
# Ok::
走子与对弈循环
use ;
use Duration;
let mut engine = builder.build;
let mv = from_iccs?;
assert!;
let reply = engine.search;
println!;
# Ok::
迭代回调
search_with 在每个完成的迭代深度触发一次回调,便于向 UI/日志流式输出:
use ;
use Duration;
let mut engine = builder.threads.build;
engine.search_with;
跨线程停止
stop_handle() 返回一个 Arc<AtomicBool>,任意线程写 true 即可请求搜索尽早返回当前最佳结果。
use ;
use Ordering;
use Duration;
let mut engine = builder.build;
let stop = engine.stop_handle;
// 在其他线程按 GUI 按钮时:
// stop.store(true, Ordering::Relaxed);
let info = engine.search;
# let _ = ;
公共 API
| 类型 | 说明 |
|---|---|
Engine / EngineBuilder |
引擎主入口,搜索与状态管理 |
Position |
不可变棋局视图(通过 engine.position() 获取) |
Move |
16 位压缩走法,支持 ICCS from_iccs / to_iccs |
Square |
0..=89 的格子索引,支持 ICCS (a0..i9) |
Piece / PieceType |
带颜色的棋子与棋子种类 |
Color |
Red / Black |
Limits |
搜索限制(深度、时间、节点) |
SearchInfo |
搜索结果快照(best_move、pv、score、nodes、nps、time) |
ChessAIError |
统一错误类型(FEN / ICCS 解析错误) |
Engine 常用方法
Engine::builder() -> EngineBuilder—hash_size(mb)、threads(n)、use_book(bool)、build()engine.set_fen(&str) -> Result<(), ChessAIError>— 加载 FEN,自动清空 TT 与历史engine.reset_to_startpos()— 复位到开局engine.fen() -> String— 导出当前 FENengine.side_to_move() -> Colorengine.legal_moves() -> Vec<Move>engine.make_move(Move) -> bool— 伪合法校验 + 将军校验engine.book_move() -> Option<Move>— 探询开局库engine.search(Limits) -> SearchInfoengine.search_with(Limits, |&SearchInfo| …) -> SearchInfoengine.stop_handle() -> Arc<AtomicBool>
项目结构
chessai/
├── Cargo.toml
├── README.md
├── LICENSE
├── assets/
│ └── BOOK.DAT # 内嵌开局库
└── src/
├── lib.rs # 公共导出
├── engine.rs # Engine / EngineBuilder
├── position.rs # 棋局状态、make/undo、Zobrist 增量更新
├── movegen.rs # 伪合法走法 / captures / quiets 生成
├── attacks.rs # 马、象、兵、士、将的攻击表
├── magic.rs # 车、炮的 Magic Bitboard 查表
├── bitboard.rs # u128 位棋盘原语与 90 格掩码
├── search.rs # Alpha-Beta、QS、迭代加深、Lazy SMP
├── picker.rs # 分阶段走法挑选器
├── see.rs # 静态交换评估
├── eval.rs # 物质 + PST 增量评估
├── tt.rs # 换位表(Zobrist 键 + lock 校验)
├── zobrist.rs # Zobrist 随机键
├── book.rs # 开局库探询
├── fen.rs # FEN 解析/生成
├── limits.rs # 搜索限制
├── mv.rs # 走法压缩表示
├── square.rs # 格子索引与 ICCS
├── piece.rs / color.rs
├── util.rs # SplitMix64 RNG
└── error.rs # ChessAIError
性能优化
- 搜索:PVS、NMP(空着裁剪)、LMR(后续走法减少)、Futility、SEE 裁剪
- 走法排序:TT 走法 → captures(MVV-LVA) → killers → countermove → history
- 换位表:Zobrist u64 键 + 32 位 lock 校验;置换策略按深度/年龄择优
- Lazy SMP:主线程 id=0 驱动回调,工作线程按 Stockfish 风格 SKIP_SIZE/SKIP_PHASE 错开深度
- 增量评估:
make_move/undo_move同步维护物质分与 PST 分,避免全盘重算
从源码构建