use crate::movegen::r#move::{Move, MoveType}; use super::{ board::PieceType, game::Game, mailbox::Mailbox, state::{Castle, State}, }; #[derive(Debug, Clone, PartialEq, Eq)] 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() } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MoveParameters { pub mv: Option, pub moved_piece: 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, moved_piece: None, captured_piece: None, promoted_piece: None, castling_ability: None, en_passant_square: None, halfmove_clock: None, } } pub fn build(game: &Game, mv: &Move) -> Self { let mut move_parameters = Self::new(); move_parameters.add_move(*mv); move_parameters.add_irreversible_parameters(game.board.state); move_parameters.add_moved_piece(&game.mailbox, mv); move_parameters.add_captured_piece(&game.mailbox, mv); move_parameters.add_promoted_piece(mv); move_parameters } fn add_move(&mut self, mv: Move) { self.mv = Some(mv); } fn add_moved_piece(&mut self, mailbox: &Mailbox, mv: &Move) { self.moved_piece = mailbox.find_piece_at(mv.src); } fn add_captured_piece(&mut self, mailbox: &Mailbox, mv: &Move) { if let MoveType::Capture | MoveType::PromotionCapture(_) = mv.move_type { self.captured_piece = mailbox.find_piece_at(mv.dst) } } fn add_promoted_piece(&mut self, mv: &Move) { if let MoveType::Promotion(promote) | MoveType::PromotionCapture(promote) = mv.move_type { self.promoted_piece = Some(promote.into_piece_type()) } } 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); } } impl Default for MoveParameters { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use crate::{ board::{fen::from_fen, square::Square}, movegen::r#move::{Move, MoveType, Promote}, }; const FEN: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/p3P1pP/P2B1Q2/1P1PNPP1/R3K2R w KQk - 0 1"; const FEN_2: &str = "1r2k2r/2P1p1qp/2npb3/1p3p2/pP2P1pP/P2B1Q2/3PNPP1/R3K2R b KQk b3 0 1"; #[test] fn test_unmake_quiet_and_double_push() -> Result<(), String> { let mut game = from_fen(FEN)?; let game_before_make = game.clone(); let mv = Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); let mv = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); Ok(()) } #[test] fn test_unmake_capture_and_promotion() -> Result<(), String> { let mut game = from_fen(FEN)?; let game_before_make = game.clone(); let mv = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); let mv = Move::new_with_type(Square::C7, Square::C8, MoveType::Promotion(Promote::Queen)); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); let mv = Move::new_with_type( Square::C7, Square::B8, MoveType::PromotionCapture(Promote::Queen), ); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); Ok(()) } #[test] fn test_unmake_en_passant() -> Result<(), String> { let mut game = from_fen(FEN_2)?; let game_before_make = game.clone(); let mv = Move::new_with_type(Square::A4, Square::B3, MoveType::EnPassant); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); Ok(()) } #[test] fn test_unmake_castle() -> Result<(), String> { let mut game = from_fen(FEN)?; let game_before_make = game.clone(); let mv = Move::new_with_type(Square::E1, Square::C1, MoveType::Castle); game.make_move(&mv); game.unmake_move(); assert_eq!(game_before_make, game); Ok(()) } }