[moves, position] Implement unmaking moves on a board
Declare an UnmakeMove trait in the moves crate, just like the MakeMove trait from an earlier commit. Implement this trait for all types that also implement BoardProvider. Bring in a whole pile of unit tests from Claude. (Holy shit, using Claude really saves time on these tests…) Several of these tests failed, and all of those failures revealed bugs in either MakeMove or UnmakeMove. Huzzah! Include fixes for those bugs here.
This commit is contained in:
parent
40e8e055f9
commit
f60cb8cf69
4 changed files with 522 additions and 10 deletions
|
@ -61,6 +61,13 @@ pub enum MakeMoveError {
|
|||
}
|
||||
|
||||
pub trait MakeMove {
|
||||
/// Make a move.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// Returns one of [`MakeMoveError`] indicating why the move could not be
|
||||
/// made.
|
||||
///
|
||||
fn make_move(&mut self, ply: Move, validate: ValidateMove) -> MakeMoveResult;
|
||||
}
|
||||
|
||||
|
@ -82,8 +89,8 @@ impl<T: BoardProvider> MakeMove for T {
|
|||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// If `validate` is [`ValidateMove::Yes`], perform validation of move correctness prior to
|
||||
/// applying the move. See [`Position::validate_move`].
|
||||
/// If `validate` is [`ValidateMove::Yes`], perform validation of move
|
||||
/// correctness prior to applying the move. See [`Position::validate_move`].
|
||||
fn make_move(
|
||||
&mut self,
|
||||
ply: Move,
|
||||
|
@ -158,14 +165,16 @@ impl<T: BoardProvider> MakeMoveInternal for T {
|
|||
.place_piece(piece, target, PlacePieceStrategy::PreserveExisting)
|
||||
.map_err(MakeMoveError::PlacePieceError)?;
|
||||
|
||||
// Capture move record before setting the en passant square, to ensure
|
||||
// board state before the change is preserved.
|
||||
let record = MoveRecord::new(board, ply, None);
|
||||
|
||||
board.en_passant_target = match target.rank() {
|
||||
Rank::FOUR => Some(Square::from_file_rank(target.file(), Rank::THREE)),
|
||||
Rank::FIVE => Some(Square::from_file_rank(target.file(), Rank::SIX)),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let record = MoveRecord::new(board, ply, None);
|
||||
|
||||
self.advance_clocks(HalfMoveClock::Advance);
|
||||
|
||||
Ok(record)
|
||||
|
@ -227,10 +236,12 @@ impl<T: BoardProvider> MakeMoveInternal for T {
|
|||
let rook = board.remove_piece(parameters.origin.rook).unwrap();
|
||||
board.place_piece(rook, parameters.target.rook, PlacePieceStrategy::default())?;
|
||||
|
||||
board.castling_rights.revoke(active_color, wing);
|
||||
|
||||
// Capture move record before revoking castling rights to ensure
|
||||
// original board state is preserved.
|
||||
let record = MoveRecord::new(board, ply, None);
|
||||
|
||||
board.castling_rights.revoke(active_color, wing);
|
||||
|
||||
self.advance_clocks(HalfMoveClock::Advance);
|
||||
|
||||
Ok(record)
|
||||
|
@ -426,7 +437,9 @@ mod tests {
|
|||
];
|
||||
|
||||
let ply = Move::double_push(Square::E2, Square::E4);
|
||||
board.make_move(ply, ValidateMove::Yes)?;
|
||||
let record = board.make_move(ply, ValidateMove::Yes)?;
|
||||
|
||||
assert_eq!(record.en_passant_target, None);
|
||||
|
||||
assert_eq!(board.get_piece(Square::E2), None);
|
||||
assert_eq!(board.get_piece(Square::E4), Some(piece!(White Pawn)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue