use crate::movegen::r#move::{Move, MoveType, Promote}; use super::{ board::{Board, Color, PieceType}, state::{Castle, State}, }; pub struct History { pub move_parameters: Vec, } impl History { pub const fn new() -> Self { Self { move_parameters: Vec::new(), } } pub fn push_move_parameters(&mut self, move_parameters: MoveParameters) { self.move_parameters.push(move_parameters) } pub fn pop_move_parameters(&mut self) -> Option { self.move_parameters.pop() } } pub struct MoveParameters { pub mv: Option, pub captured_piece: Option, pub promoted_piece: Option, pub castling_ability: Option<[Castle; 2]>, pub en_passant_square: Option, pub halfmove_clock: Option, } impl MoveParameters { pub const fn new() -> Self { Self { mv: None, captured_piece: None, promoted_piece: None, castling_ability: None, en_passant_square: None, halfmove_clock: None, } } pub fn build(board: &Board, mv: &Move) -> Self { let mut move_parameters = Self::new(); move_parameters.add_move(*mv); move_parameters.add_irreversible_parameters(board.state); move_parameters.add_capture_and_promotion_piece(board, *mv, board.state.current_player()); move_parameters } fn add_move(&mut self, mv: Move) { self.mv = Some(mv) } fn add_captured_piece(&mut self, board: &Board, dst: usize, color: Color) { self.captured_piece = board.piece_type_at(dst, color); } fn add_promoted_piece(&mut self, promote: Promote) { self.promoted_piece = Some(promote.into_piece_type()) } pub fn add_irreversible_parameters(&mut self, state: State) { self.castling_ability = Some(state.castling_ability); self.en_passant_square = state.en_passant_square; self.halfmove_clock = Some(state.halfmove_clock) } pub fn add_capture_and_promotion_piece(&mut self, board: &Board, mv: Move, color: Color) { match mv.move_type { MoveType::Capture => self.add_captured_piece(board, mv.dst, color.opponent()), MoveType::Promotion(piece) => self.add_promoted_piece(piece), MoveType::PromotionCapture(piece) => { self.add_promoted_piece(piece); self.add_captured_piece(board, mv.dst, color.opponent()); } _ => (), } } } #[cfg(test)] mod tests { use crate::{ board::{fen::from_fen, history::MoveParameters, square::Square}, movegen::r#move::{Move, MoveType, Promote}, }; const FEN: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/p3P1pP/P2B1Q2/1P1PNPP1/R3K2R w KQk - 0 1"; #[test] fn test_unmake_quiet_and_double_push() -> Result<(), String> { let mut game = from_fen(FEN)?; let board_before_make = game.board.clone(); let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); Ok(()) } #[test] fn test_unmake_capture_and_promotion() -> Result<(), String> { let mut game = from_fen(FEN)?; let board_before_make = game.board.clone(); let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); let mv = Move::new_with_type( Square::C7, Square::B8, MoveType::PromotionCapture(Promote::Queen), ); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); Ok(()) } #[test] fn test_unmake_en_passant() -> Result<(), String> { let mut game = from_fen(FEN)?; let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); game.board.make_move(&mv); let board_before_make = game.board.clone(); let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); Ok(()) } #[test] fn test_unmake_castle() -> Result<(), String> { let mut game = from_fen(FEN)?; let board_before_make = game.board.clone(); let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle); let mut move_parameters = MoveParameters::new(); move_parameters.add_move(mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_capture_and_promotion_piece(&game.board, mv, game.current_player()); game.board.make_move(&mv); game.board.unmake_move(move_parameters); assert_eq!(board_before_make, game.board); Ok(()) } }