# 项目开发建议与性能优化记录

本文档面向 `Python_chinese_chess` 的后续开发，包含：架构现状、已完成的性能优化、后续开发方向与建议。

---

## 一、架构现状

```
main.py
 └── chinese_chess/
     ├── constants.py   常量、资源路径（不依赖 pygame）
     ├── fonts.py       中文字体管理（候选字体名 + 字体文件兜底）
     ├── pieces.py      走法规则 + Board 局面（纯逻辑，不依赖 pygame）
     │                  - 七种棋子的走法函数（模块级，AI/界面共用）
     │                  - Board：color/kind 双矩阵，move/unmove（可撤销）
     │                  - 快速将军检测（从将反向查攻击者）
     │                  - legal_moves_with_check（过滤送将）/ all_legal_moves
     ├── ai.py          Alpha-Beta 搜索（negamax + 迭代加深 + 时间预算）
     ├── board.py       棋盘/棋子渲染（pygame）
     ├── button.py      按钮控件
     └── game.py        游戏主循环（事件、AI 线程、渲染）
assets/s2/              棋子图片（r_rook.gif ... 统一小写英文名）
tests/                  单元测试（不依赖 pygame，可脱离图形环境跑）
backup/                 旧版平铺代码备份
```

**关键设计原则**
- 逻辑（pieces/ai）与渲染（board/game）解耦 → 规则可单测、AI 可离线调试
- 走法规则只写一份（模块函数），棋子对象与 AI 共用，避免两处实现漂移
- 搜索用 make/unmake 就地走子，不复制棋盘

## 二、本次性能优化（2026-08-14）

### 卡顿来源与优化

| 问题 | 处理 | 效果 |
| --- | --- | --- |
| AI 搜索深度 3 开局耗时 4.07s | ① 快速将军检测：从将反向查攻击者（车/炮/马/兵/飞将），替代全盘 90 格扫描 | `is_in_check` 快 2.5x |
| 每走法一次 `board.copy()`（180 次赋值） | ② `Board.move/unmove` 就地走子+撤销，搜索零拷贝 | depth3: 4.07s → **1.01s（4x）** |
| 固定深度导致思考时间不可控 | ③ 迭代加深 + 节点级时间检查（每 1024 节点，超时抛异常返回当前最佳） | 2s 预算严格 ~2.05s 返回 |
| AI 思考时界面完全冻结 | ④ AI 放入后台线程（daemon），主线程持续渲染；`time.sleep(0)` 让出 GIL | 思考期间界面可刷新、可点"重新开始" |
| 每帧重算选中走法 / 将军检测 | ⑤ 渲染缓存：`selected_moves` 选子时算一次；`check_status` 走子后更新 | 渲染循环零重复搜索 |

### 优化后基准（开局 32 子，Windows / Python 3.9）

| 项 | 优化前 | 优化后 |
| --- | --- | --- |
| depth 2 | 0.20s | 0.06s |
| depth 3 | 4.07s | 1.01s |
| 思考时间预算（2s） | 不可控（3-6s） | 2.01–2.13s |

### 性能调参入口

`chinese_chess/ai.py`
- `DEFAULT_TIME_BUDGET = 2.0`：默认思考秒数（难度-速度平衡）
- `get_best_move(..., depth=4, max_time=2.0)`：最大深度与预算

## 三、后续开发建议

### 1. 功能层（按性价比排序）

- **悔棋 / 复盘**：游戏层维护走法历史栈（`move` + 被吃子信息已具备），悔棋只需 `board.unmove` + 恢复 pieces 列表，改动小收益大
- **棋谱记录/导出**：把走法历史输出为通用格式（如 `1. 炮二平五 马8进7 ...`），便于复盘与分享；可加"人机对弈棋谱自动保存"
- **AI 难度选择**：入口界面 3 档（弱=1s/浅层、中=2s、强=4s+深层），或直接暴露 `max_time`/`depth` 选项
- **开局库**：内置常见开局（中炮、屏风马等）前 4-6 步走法表，开局秒应且更专业
- **音效**：走子、吃子、将军提示音（pygame.mixer），低成本提升体验
- **双人对战 / AI 观战**：复用现有逻辑，只需切换"轮到谁"由 AI 还是人类控制
- **残局题库**：加载 FEN 类似格式的局面，练残局杀法

### 2. 架构层

- **状态机化**：当前 `game.py` 用 flag 区分局面；建议引入显式状态（`MENU / PLAYING / AI_THINKING / GAME_OVER`），事件集中分发，扩展菜单/设置页更稳
- **引擎与界面解耦**：把 `get_best_move` 封装成"引擎接口"（`Engine.get_best_move(board, budget)`），便于：换更强引擎、在子进程中跑（规避 GIL）、接 UCI/XQW 协议对弈外部引擎
- **配置化**：`constants.py` 中的难度/时间/窗口尺寸等收敛为 `config.py` 或 JSON 配置
- **事件总线（可选）**：走子/吃子/将军/终局广播事件，音效、日志、UI 各自订阅，解耦新增功能

### 3. AI 层（棋力提升路线）

当前：子力 + 位置加成评估，negamax + Alpha-Beta + 吃子优先排序，depth 3-4。

按收益排序的增强：
1. **置换表（Transposition Table）**：Zobrist 哈希 + 局面缓存，避免重复搜索相同局面，深度 4+ 提速显著（实现约 100 行）
2. **空着裁剪（Null Move Pruning）**：非将军局面跳过一步搜索，棋力/速度双升（需配合将死安全）
3. **杀手走法 / 历史启发**：除吃子排序外，缓存同深度剪枝走法，改善走法顺序、增强剪枝
4. **评估细化**：更细的位置价值表（车马炮兵分阶段）、双象加成、过河兵数量、将帅安全性（周围子力密度）
5. **自我对弈调参**：写 `selftest` 脚本让新旧版本对弈 N 局，统计胜率/ELO，量化每次改动棋力变化（强烈建议在改动 AI 前先建立）
6. **开局库 + 残局库**：跳过开局搜索浪费；残局用表库直接查杀法

### 4. 工程层

- **打包**：`pyinstaller --onefile --noconsole main.py` + 资源路径处理（`assets` 用 `sys._MEIPASS` 兼容），交付 exe 给无 Python 环境的同学
- **CI**：GitHub Actions 跑 `python -m unittest`（逻辑测试无需 pygame）；需要显示测试时用 `SDL_VIDEODRIVER=dummy` 冒烟
- **类型注解**：已部分覆盖；建议全量补全 + `mypy` 校验
- **日志**：AI 思考日志（深度、耗时、评估值）默认关闭、`--debug` 开启，便于调参
- **性能 profiling**：`python -m cProfile -s cumtime` 定位热点后再优化，避免凭感觉

### 5. 测试层

- **走法完备性**：增加"吃将即赢/被将军必须应将/不允许送将"的针对性用例
- **模糊对局测试**：随机走 N 局，断言：无异常、终局必为 将死/困毙/正常结束
- **AI 棋力回归**：固定局面集（如开局、中局、残局杀法各 10 局），断言 AI 走法合理（吃子/将军/不送将），防止优化破坏
- **性能回归**：CI 中跑 depth3 开局，断言 < 3s（可配 `--slow` 跳过）

## 四、程序级改进清单（代码层面，2026-08-14 补充）

### 已修复 / 已落地（2026-08-14）
- **重新开始竞态**：AI 在后台线程思考时点“重新开始”，旧线程完成后会把过时走法下到新对局。已用 `epoch` 局面代次校验丢弃过期结果（game.py）。
- **状态机化**：显式状态 `STATE_PLAYING / STATE_AI_THINKING / STATE_GAME_OVER`（game.py），替代 flag 组合。
- **悔棋**：走法历史栈 + “悔棋”按钮 / U 键，支持吃子恢复（undo_move，board 与 pieces 同步回滚）。
- **引擎接口抽象**：`engine.py` 定义 `Engine` 协议 + `AlphaBetaEngine` 实现，game.py 通过接口调用，可替换外部引擎。
- **AI 置换表 + 历史启发**：Zobrist 哈希（zobrist.py，Board 增量维护 zhash）+ TT（EXACT/LOWER/UPPER + 最佳走法缓存）+ 剪枝走法记功排序。depth4 8.35s → 3.96s。
- **将帅位置缓存**：Board 维护 `_red_king/_black_king`（place/remove/move/unmove/copy 同步），`find_king` O(1)。
- **git 版本管理**：已 init 并首次提交（v2.2.0 基线）。

### 建议（按优先级）

| 优先级 | 位置 | 改进 | 说明 |
| --- | --- | --- | --- |
| 高 | game.py | 状态机化 | 用显式状态（MENU/PLAYING/AI_THINKING/GAME_OVER）替代 flag，为菜单/设置页铺路 |
| 高 | game.py | 悔棋 | 走法历史栈已可支撑（Board.unmove + 被吃子信息），加按钮/快捷键即可 |
| 高 | 新文件 | 引擎接口抽象 | `Engine.get_best_move(board, budget)` 接口，自研 AI 实现；后续可接 UCI/外部引擎 |
| 中 | ai.py | 走法排序优化 | 每节点 `sorted()` 开销明显；可只把吃子走法置前 + 历史启发，减少排序成本 |
| 中 | ai.py | 置换表 | Zobrist 哈希缓存局面，depth4+ 提速显著 |
| 中 | ai.py | 迭代加深传 PV | 用上一层最佳走法作为首候选，增强剪枝 |
| 中 | pieces.py | 王位置缓存 | `find_king` 每步全盘扫描；move/unmove 维护将帅位置可再提速 |
| 中 | 工程 | git 初始化 | 项目尚无版本管理，建议 `git init` + 首次提交 |
| 中 | 工程 | pyproject.toml | 使项目可 `pip install -e .`，依赖/入口规范化 |
| 低 | 工程 | pyinstaller 打包 | 交付 exe（需处理 assets 路径） |
| 低 | 功能 | 音效 | 走子/吃子/将军提示（pygame.mixer） |

## 五、当前已知限制

- 搜索为单线程 Python 实现，depth 4+ 在开局阶段仍偏慢（可用 2s 预算 + 迭代加深缓解，不追求极致棋力）
- 无将军限步（长将/长捉判和规则），AI 可能循环长将；后续可加重复局面检测（配合置换表实现简单）
- 无棋谱导入/导出、无开局库（见功能建议）
