213 lines
7.0 KiB
Rust
213 lines
7.0 KiB
Rust
use crate::movegen::r#move::{Move, MoveType, Promote};
|
|
|
|
use super::{
|
|
board::{Board, Color, PieceType},
|
|
state::{Castle, State},
|
|
};
|
|
|
|
pub struct History {
|
|
pub move_parameters: Vec<MoveParameters>,
|
|
}
|
|
|
|
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<MoveParameters> {
|
|
self.move_parameters.pop()
|
|
}
|
|
}
|
|
|
|
pub struct MoveParameters {
|
|
pub mv: Option<Move>,
|
|
pub captured_piece: Option<PieceType>,
|
|
pub promoted_piece: Option<PieceType>,
|
|
pub castling_ability: Option<[Castle; 2]>,
|
|
pub en_passant_square: Option<usize>,
|
|
pub halfmove_clock: Option<u8>,
|
|
}
|
|
|
|
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(())
|
|
}
|
|
}
|