Files
zeal/src/board/history.rs

183 lines
5.0 KiB
Rust

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<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()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MoveParameters {
pub mv: Option<Move>,
pub moved_piece: Option<PieceType>,
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,
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(())
}
}