# moonchess 设计说明

本文说明 moonchess 的整体结构、关键数据结构与算法选择，以及相对参考项目 chess.js 的取舍。

## 1. 总体结构

库分为三层，均由 MoonBit 实现，不依赖平台特定代码：

- **表示层**：`types` / `square` / `board` —— 类型、坐标、棋盘与攻击检测。
- **规则层**：`game` / `movegen` / `pgn` —— 局面状态、走法生成、记谱。
- **搜索层**：`engine` / `search` / `book` —— 评估、α-β 搜索、置换表、开局库。

`display` 提供渲染，`cmd/main` 与 `examples/demo` 是上层示例。

## 2. 棋盘表示：0x88

棋盘是长度 128 的一维数组，用 `rank * 16 + file` 编码格子。每个 nibble 只用低 4 位有效，
因此“是否在棋盘内”可由一次掩码判定：

```text
on_board(sq) == ((sq & 0x88) == 0)
```

好处是所有滑动与跳跃方向都可以写成整数偏移（如马为 `±14, ±18, ±31, ±33`），越界自动被掩码
过滤，无需在每步单独做边界判断。代价是数组有一半空间是“洞”，在 128 的规模下可以忽略。

## 3. 攻击检测与合法性

`is_attacked(board, sq, by_color)` 从被检测格出发，用偏移向外探测：

- 兵：根据颜色检查斜下方的两个格子；
- 马、王：遍历跳跃偏移；
- 象/车/后：沿对应方向滑动，遇到第一个子即停。

合法走法的判定采用“走后验证”：先生成伪合法走法，`make_move` 后检查己方王是否被攻击，
再 `undo_move`。这比单独实现钉住/闪击分析更简单，也更容易对齐标准 perft。

## 4. 状态与撤销

`Chess` 持有棋盘、走子方、易位权（4 位掩码）、吃过路兵目标格、半回合计数、回合数，以及：

- `castle_rook`：四个易位权各自对应的车所在 file。它在一局中固定不变，使 Chess960 的任意
  易位起点也能正确生成走法、落子与撤销（易位由 flags 标记，而非“王走了两格”）；
- `history`：撤销栈，每个条目保存走法、走子前的易位权 / ep / 计数器，以及被吃子的实际格子与
  内容（用于恢复，尤其区分普通吃子与吃过路兵）；
- `positions`：位置键序列，用于三方重复判定。

`make_move` 的关键次序是**先移走被吃子再落子**：普通吃子的被吃格恰好等于目标格，若先落子再
“清空被吃格”会把刚落下的子删掉。设计上把“被吃格”在撤销条目中显式记录，使吃过路兵（被吃格
与目标格不同）与普通吃子统一处理。

## 5. 记谱

- **SAN**：生成时做同类同目标格的消歧（文件、行、或完整格名），附加 `+` / `#`；`+`/`#` 通过
  走子后判断对方是否被将军/将杀得到。
- **FEN**：解析/生成棋盘、走子方、易位权、ep、半回合与回合数。
- **PGN**：输出七个标签对与按宽度折行的走子文本；解析时先剥离注释 `{}` 与变例 `()`，跳过
  NAG `$n` 与内联回合号，并容忍缺失的 `+`/`#`。

## 6. 搜索

- **评估**：子力价值 + 棋子位置表（pawn/knight/bishop/rook/queen/king），并计入象对奖励与叠兵
  惩罚，从白方视角计算。
- **negamax + α-β**：叶节点进入**静止搜索**（只扩展吃子）以缓解水平线效应；走法依次按
  置换表着法、杀手着法（每层两个导致剪切的安静着法）、吃子（MVV-LVA）与历史启发排序。
- **置换表**：以 64 位 Zobrist 哈希为键，2^16 项，存深度、分值、界类型（exact/lower/upper）
  与最佳走子来源格，用于剪切与排序。
- **迭代加深**：`Searcher::search` 逐层加深，`search_timed` 在根节点之间检查时间预算，超时则
  保留上一层已完成的结果。

Zobrist 键由 splitmix64 生成的确定性伪随机表构成（子力×颜色×格子、走子方、易位权、ep 文件），
保证可复现。

## 7. 开局库

以 SAN 历史为键：库内保存若干开局线路，查询时用当前历史的 SAN 前缀匹配线路，返回第一个合法
续着。实现简单、可读，便于后续替换为 ECO 文件或带权重的数据库。

## 8. 测试与正确性

走法生成的正确性以 **perft** 为准，覆盖公开标准局面（初始局面、Kiwipete、Position 3–6），
并用“快速生成器 vs 基于 SAN 的生成器计数一致”做交叉验证。其余测试覆盖 FEN、SAN、PGN、
易位、吃过路兵、升变、撤回、将杀/逼和/和棋、Zobrist 哈希、引擎与开局库。

## 9. 与 chess.js 的取舍

- 接口风格对齐 `Chess` / `Move` / SAN / FEN，降低迁移成本；
- 内部不复刻其对象与服务结构，改用更贴合 MoonBit 的值类型与包组织；
- chess.js 不含 AI，本项目补充评估、α-β、置换表与开局库，形成“库 + 引擎”的差异化；
- 支持 Chess960（X-FEN / Shredder-FEN 与任意易位起点），与 chess.js 的 960 能力对齐。

## 10. 后续工作

- 引擎：分配时间到子节点、杀手着法扩展与评估参数自对弈调优；
- 开局库：外部 ECO 数据与权重；
- 一致性测试：与成熟的 960 perft 参考数据对拍。
