# Gobang v2.0 — Rust 重写设计规格 ## 概述 将 Gobang(五子棋)从 C + IUP + CMake 全面迁移到 Rust + Tauri + React + TypeScript, 参考 PathEditor 项目的 workspace 架构、工具链约定和开源规范。 ## 技术栈 | 层 | 技术 | |----|------| | 核心引擎 | Rust (edition 2021, `stable-x86_64-pc-windows-gnu`) | | 桌面框架 | Tauri 2.x | | 前端 | React 19 + TypeScript strict + Vite | | 网络 | renet(Rust 原生 ENet 协议实现) | | 状态管理 | Zustand | | 国际化 | i18next (zh-CN / en) | | 包管理 | npm(前端)+ Cargo(Rust) | ## Crate 结构 ``` Gobang/ ├── core/ # Rust 库 crate(纯逻辑,零 Tauri 依赖) │ └── src/ │ ├── board.rs # 棋盘状态、落子验证、胜负判定 │ ├── rules.rs # 禁手规则 │ ├── ai/ # 传统算法 AI │ │ ├── mod.rs │ │ ├── evaluate.rs # 棋形评分 │ │ └── search.rs # Alpha-Beta 搜索 │ ├── network.rs # renet 网络对战 │ ├── record.rs # 棋谱记录与回放 (JSON) │ ├── llm.rs # 大模型 API 客户端 │ └── lib.rs ├── gui/ # Tauri 桌面应用(薄层) │ └── src/ │ ├── commands.rs # #[tauri::command] → core API │ ├── lib.rs │ └── main.rs ├── src/ # React 前端 (TypeScript strict) │ ├── core/ # 前端纯逻辑(坐标转换、棋型常量) │ ├── components/ │ │ ├── board/ # Canvas 棋盘渲染 │ │ ├── menu/ # 主菜单、设置 │ │ ├── game/ # 对局 UI │ │ └── replay/ # 棋谱回放 │ ├── hooks/ # useGame, useTimer, useAI │ ├── store/ # Zustand 状态管理 │ └── i18n/ # 中/英 ├── Cargo.toml # workspace 根 ├── rust-toolchain.toml # stable-x86_64-pc-windows-gnu ├── package.json ├── LICENSE # MIT ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── SECURITY.md └── README.md ``` ## 功能清单 v1.0 全部功能保留,Rust 重写: | 模块 | 功能 | 实现位置 | |------|------|----------| | 本地双人 | 同机两人轮流落子 | core/board.rs | | 传统 AI | 5 级难度、禁手规则、Alpha-Beta 搜索 | core/ai/ | | LLM AI | 大模型 API 接入对战 | core/llm.rs | | 网络对战 | renet P2P 联机 | core/network.rs | | 棋谱回放 | 对局记录 (JSON) 与复盘 | core/record.rs | | 计时器 | 每回合限时(可选) | gui + frontend | | 悔棋 | 撤销指定步数 | core/board.rs | ## core crate 设计 ### board.rs — 棋盘引擎 不可变风格核心抽象。每次落子返回新棋盘,通过 `Cow` 优化内存: ```rust pub struct Board { size: usize, cells: [[CellState; MAX_SIZE]; MAX_SIZE], } pub enum CellState { Empty, Black, White } impl Board { pub fn place(&self, pos: Position, color: Color) -> Result; pub fn check_win(&self, pos: Position) -> bool; pub fn is_forbidden(&self, pos: Position) -> bool; pub fn get_candidate_moves(&self) -> Vec; } ``` - `MoveError` 枚举:`OutOfBounds`, `Occupied`, `ForbiddenMove`, `GameOver` - `place()` 不修改 self,返回新 Board 或错误 - 胜负判断:四方向连续扫描(复用 v1 的 DirInfo 思路,改为 Rust 迭代器) - 禁手检测:长连、双三、双四检查 ### ai/ 模块 — 传统 AI Trait 抽象,支持 AI 引擎切换: ```rust pub trait AiEngine: Send + Sync { fn best_move(&self, board: &Board, color: Color) -> Option; } pub struct AlphaBetaAi { depth: usize, defense_coefficient: f64, } ``` - `evaluate.rs`:棋形打分(连五、活四、冲四、活三、眠三、活二) - `search.rs`:Alpha-Beta 剪枝 + 迭代加深 + 启发式落子排序 - 难度 1-5 通过 depth 参数控制 ### network.rs — renet 网络对战 ```rust pub enum GameMessage { Move { pos: Position, turn: u32 }, Undo { steps: u32 }, Resign, Chat(String), } pub struct NetworkSession { // renet client/server handle } ``` - 服务端创建房间,客户端加入 - 可靠 UDP 传输,和原 ENet 行为一致 - 掉线检测 + 重连 ### record.rs — 棋谱 (JSON) ```json { "version": "2.0", "date": "2026-05-30", "board_size": 15, "players": { "black": "Human", "white": "AI-Lv3" }, "moves": [{"x": 7, "y": 7, "color": "Black"}, ...], "result": "Black Win" } ``` - 序列化/反序列化用 `serde` + `serde_json` - 回放:按步加载 move 历史,前端逐帧展示 ### llm.rs — 大模型 AI - HTTP 客户端(`reqwest`)调用 OpenAI 兼容 API - 将棋盘状态序列化为 prompt,解析模型回复的坐标 - 实现 `AiEngine` trait,可替换 AlphaBetaAi ## gui crate — Tauri 命令层 薄层,每个 `#[tauri::command]` 一行调用 core: ```rust #[tauri::command] fn place_piece(state: State, x: usize, y: usize) -> Result { let mut game = state.game.lock().map_err(|e| e.to_string())?; game.place(x, y).map_err(|e| e.to_string()) } ``` 全局状态管理: ```rust struct AppState { game: Mutex, } enum GameMode { Local, VsAi(Box), Online(NetworkSession), Replay(ReplayState), } ``` IPC 命令清单: | Command | 参数 | 返回值 | 功能 | |---------|------|--------|------| | `new_game` | `mode, board_size, config` | `Result<(), String>` | 开始新局 | | `place_piece` | `x, y` | `Result` | 落子 | | `undo` | `steps` | `Result<(), String>` | 悔棋 | | `get_board` | — | `Board` | 获取棋盘状态 | | `ai_move` | — | `Result` | 请求 AI 走棋 | | `connect_game` | `ip, port` | `Result<(), String>` | 网络连接 | | `send_message` | `msg` | `Result<(), String>` | 网络消息 | | `save_record` | `path` | `Result<(), String>` | 保存棋谱 | | `load_record` | `path` | `Result` | 加载棋谱 | | `get_game_config` | — | `GameConfig` | 读取设置 | ## 前端设计 ### 组件树 ``` App ├── MainMenu │ ├── LocalGameSetup # 本地双人 │ ├── AiGameSetup # 难度、先手、禁手开关 │ ├── OnlineSetup # IP:端口 / 创建房间 │ └── LoadReplay # 加载棋谱文件 ├── GameView │ ├── BoardCanvas # Canvas 棋盘 + 点击落子 │ ├── GameInfo # 当前玩家、AI 思考中、胜负提示 │ ├── TimerDisplay # 倒计时(可选) │ └── GameControls # 悔棋、认输、保存 └── ReplayView ├── BoardCanvas # 只读棋盘 ├── StepSlider # 步数滑条 └── ReplayControls # 播放/暂停/快进 ``` ### 数据流 ``` 用户点击棋盘 → BoardCanvas.onClick → store.placePiece(x, y) → invoke('place_piece', {x, y}) # Tauri IPC → gui/commands.rs → core::Board::place() → store 更新 board / currentColor → React 重渲染 BoardCanvas ``` ### Canvas 渲染要点 - `useRef` + `requestAnimationFrame` - 棋盘线、棋子(渐变填充仿木纹风格)、最后一手高亮标记 - 坐标纯函数:`boardToCanvas(pos, cellSize, padding) → {x, y}` - 支持窗口 resize 自适应棋盘大小 ### 状态管理 (Zustand) ```typescript interface GameStore { mode: GameMode; board: CellState[][]; currentColor: Color; moves: Move[]; gameStatus: 'waiting' | 'playing' | 'ai_thinking' | 'game_over'; winner: Color | null; // actions startGame: (config: GameConfig) => Promise; placePiece: (x: number, y: number) => Promise; undo: () => Promise; loadReplay: (path: string) => Promise; } ``` ## 错误处理策略 | 层 | 策略 | |----|------| | **core** | `Result` / `Result`,中文错误消息 | | **gui** | `Result`,`to_string()` 转换,Tauri 自动序列化 | | **前端** | `.catch()` 显示错误 toast,`isSaving` 防并发点击 | ## 构建与测试 ```bash # 开发模式 npm install npx tauri dev # Rust 检查 cargo check cargo clippy -- -D warnings cargo fmt --check # 测试 cargo test # Rust 单元测试 npm test # 前端单元测试 (Vitest) # 生产构建 npx tauri build ``` ### 测试覆盖率目标:80%+ ## 与 PathEditor 一致的设计决策 - **工具链**:`stable-x86_64-pc-windows-gnu` - **Workspace**:`resolver = "2"`, edition 2021 - **前端**:TypeScript strict, Vitest, i18next - **开源文件**:LICENSE (MIT), CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, SECURITY.md - **提交格式**:约定式提交(`feat:`, `fix:`, `refactor:` 等) - **版本管理**:`Cargo.toml` workspace.package.version + `package.json` version 集中管理