diff --git a/core/src/board.rs b/core/src/board.rs index 43f65ef..6c5c238 100644 --- a/core/src/board.rs +++ b/core/src/board.rs @@ -99,7 +99,7 @@ impl Board { /// 悔棋 — 撤销最近一步 pub fn undo(&self) -> Result { if self.history.is_empty() { - return Err(MoveError::GameOver); + return Err(MoveError::NoHistory); } let mut new_board = self.clone(); let last_move = new_board.history.pop().unwrap(); @@ -253,9 +253,14 @@ mod tests { } #[test] - fn test_undo_empty_history() { + fn test_undo_empty_history_returns_no_history_error() { let board = Board::new(15); - assert_eq!(board.undo(), Err(MoveError::GameOver)); + let result = board.undo(); + assert!(result.is_err()); + match result { + Err(MoveError::NoHistory) => {}, + other => panic!("expected NoHistory, got {:?}", other), + } } #[test] diff --git a/core/src/types.rs b/core/src/types.rs index 564ef1f..714d04d 100644 --- a/core/src/types.rs +++ b/core/src/types.rs @@ -68,6 +68,7 @@ pub enum MoveError { Occupied, ForbiddenMove, GameOver, + NoHistory, } impl std::fmt::Display for MoveError { @@ -77,6 +78,7 @@ impl std::fmt::Display for MoveError { MoveError::Occupied => "该位置已有棋子", MoveError::ForbiddenMove => "禁手位置,不能落子", MoveError::GameOver => "游戏已结束", + MoveError::NoHistory => "没有可撤销的棋子", }; write!(f, "{}", msg) } diff --git a/gui/src/commands.rs b/gui/src/commands.rs index 948f77f..df64fce 100644 --- a/gui/src/commands.rs +++ b/gui/src/commands.rs @@ -94,7 +94,10 @@ pub fn undo(steps: u32, state: State) -> Result<(), String> { let mut board_opt = state.board.lock().map_err(|e| e.to_string())?; let mut board = board_opt.clone().ok_or("游戏未开始")?; - for _ in 0..steps * 2 { + let max_undo = board.history().len() as u32; + let actual_steps = (steps * 2).min(max_undo); + + for _ in 0..actual_steps { board = board.undo().map_err(|e| e.to_string())?; }