Change History and Mailbox to tuple structs, use builder pattern for Move_Info

This commit is contained in:
stefiosif
2025-02-04 19:19:17 +02:00
parent 77660d21f8
commit 55056537f3
3 changed files with 79 additions and 94 deletions

View File

@@ -7,7 +7,7 @@ use String as FenError;
use super::{
board::{Board, Color, PieceType},
history::{History, MoveParameters},
history::{History, MoveInfo},
mailbox::Mailbox,
square::Square,
state::Castle,
@@ -57,8 +57,17 @@ impl Game {
}
pub fn make_move(&mut self, mv: &Move) {
self.history
.push_move_parameters(MoveParameters::build(self, mv));
let move_info = MoveInfo::new()
.with_move(*mv)
.with_castling_ability(self.board.state.castling_ability)
.with_en_passant_square(self.board.state.en_passant_square)
.with_halfmove_clock(self.board.state.halfmove_clock)
.with_moving_piece(&self.mailbox, mv)
.with_captured_piece(&self.mailbox, mv)
.with_promoted_piece(mv, self.current_player())
.with_zobrist_hash(&self.hash);
self.history.push_move_info(move_info);
let board = &mut self.board;
let hash = &mut self.hash;
@@ -167,27 +176,27 @@ impl Game {
pub fn unmake_move(&mut self) {
let board = &mut self.board;
let mailbox = &mut self.mailbox;
let move_parameters = &mut self
let move_info = &mut self
.history
.pop_move_parameters()
.pop_move_info()
.expect("History stack is empty");
let color_before_move = board.state.change_side();
board.state.revert_full_move(color_before_move);
board.state.en_passant_square = move_parameters.en_passant_square;
board.state.en_passant_square = move_info.en_passant_square;
if let Some(hash) = move_parameters.zobrist_hash {
if let Some(hash) = move_info.zobrist_hash {
self.hash = hash;
}
if let Some(new_castling_ability) = move_parameters.castling_ability {
if let Some(new_castling_ability) = move_info.castling_ability {
board.state.castling_ability = new_castling_ability;
}
if let Some(new_halfmove_clock) = move_parameters.halfmove_clock {
if let Some(new_halfmove_clock) = move_info.halfmove_clock {
board.state.halfmove_clock = new_halfmove_clock;
}
let mv = move_parameters
let mv = move_info
.mv
.expect("Expected move parameters from history stack");
let piece_at_dst = mailbox.piece_at(mv.dst()).expect("No piece at dst.");
@@ -198,19 +207,19 @@ impl Game {
mailbox.set_piece_at(mv.dst(), None);
}
MoveType::Capture => {
let captured_piece = move_parameters
let captured_piece = move_info
.captured_piece
.expect("Expected captured piece to unmake Capture");
board.move_piece(mv.dst(), mv.src(), piece_at_dst.0);
board.insert_opponent_piece(mv.dst(), captured_piece.0);
mailbox.set_piece_at(mv.src(), move_parameters.moving_piece);
mailbox.set_piece_at(mv.src(), move_info.moving_piece);
mailbox.set_piece_at(mv.dst(), Some(captured_piece));
}
MoveType::PromotionKnight
| MoveType::PromotionBishop
| MoveType::PromotionRook
| MoveType::PromotionQueen => {
let promoted_piece = move_parameters
let promoted_piece = move_info
.promoted_piece
.expect("Expected promoted piece to unmake Promotion");
board.remove_own_piece(mv.dst(), promoted_piece.0);
@@ -223,10 +232,10 @@ impl Game {
| MoveType::PromotionCaptureBishop
| MoveType::PromotionCaptureRook
| MoveType::PromotionCaptureQueen => {
let promoted_piece = move_parameters
let promoted_piece = move_info
.promoted_piece
.expect("Expected promoted piece to unmake PromotionCapture");
let captured_piece = move_parameters
let captured_piece = move_info
.captured_piece
.expect("Expected captured piece to unmake PromotionCapture");
board.remove_own_piece(mv.dst(), promoted_piece.0);
@@ -266,10 +275,14 @@ impl Game {
}
pub fn make_null_move(&mut self) {
let move_params = MoveParameters::build_null(self);
self.history.push_move_parameters(move_params);
self.hash.update_side_to_move_key();
let move_info = MoveInfo::new()
.with_castling_ability(self.board.state.castling_ability)
.with_en_passant_square(self.board.state.en_passant_square)
.with_halfmove_clock(self.board.state.halfmove_clock)
.with_zobrist_hash(&self.hash);
self.history.push_move_info(move_info);
self.hash.update_side_to_move_key();
self.board
.state
.update_null_game_state(self.current_player());
@@ -277,25 +290,25 @@ impl Game {
pub fn unmake_null_move(&mut self) {
let board = &mut self.board;
let move_parameters = &mut self
let move_info = &mut self
.history
.pop_move_parameters()
.pop_move_info()
.expect("History stack is empty");
let color_before_move = board.state.change_side();
board.state.revert_full_move(color_before_move);
board.state.en_passant_square = move_parameters.en_passant_square;
board.state.en_passant_square = move_info.en_passant_square;
if let Some(hash) = move_parameters.zobrist_hash {
if let Some(hash) = move_info.zobrist_hash {
self.hash = hash;
}
if let Some(new_castling_ability) = move_parameters.castling_ability {
if let Some(new_castling_ability) = move_info.castling_ability {
board.state.castling_ability = new_castling_ability;
}
if let Some(new_halfmove_clock) = move_parameters.halfmove_clock {
if let Some(new_halfmove_clock) = move_info.halfmove_clock {
board.state.halfmove_clock = new_halfmove_clock;
}
}

View File

@@ -2,34 +2,29 @@ use crate::movegen::r#move::{Move, MoveType};
use super::{
board::{Color, PieceType},
game::Game,
mailbox::Mailbox,
state::{Castle, State},
state::Castle,
zobrist::ZobristHash,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct History {
pub move_parameters: Vec<MoveParameters>,
}
pub struct History(Vec<MoveInfo>);
impl History {
pub const fn new() -> Self {
Self {
move_parameters: Vec::new(),
}
Self(Vec::new())
}
pub fn push_move_parameters(&mut self, move_parameters: MoveParameters) {
self.move_parameters.push(move_parameters);
pub fn push_move_info(&mut self, move_info: MoveInfo) {
self.0.push(move_info);
}
pub fn pop_move_parameters(&mut self) -> Option<MoveParameters> {
self.move_parameters.pop()
pub fn pop_move_info(&mut self) -> Option<MoveInfo> {
self.0.pop()
}
pub fn in_repetition(&self, hash: ZobristHash) -> bool {
self.move_parameters
self.0
.iter()
.rev()
.skip(1)
@@ -38,8 +33,8 @@ impl History {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MoveParameters {
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct MoveInfo {
pub mv: Option<Move>,
pub moving_piece: Option<(PieceType, Color)>,
pub captured_piece: Option<(PieceType, Color)>,
@@ -50,55 +45,37 @@ pub struct MoveParameters {
pub zobrist_hash: Option<ZobristHash>,
}
impl MoveParameters {
pub const fn new() -> Self {
Self {
mv: None,
moving_piece: None,
captured_piece: None,
promoted_piece: None,
castling_ability: None,
en_passant_square: None,
halfmove_clock: None,
zobrist_hash: None,
}
impl MoveInfo {
pub fn new() -> Self {
Self::default()
}
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_moving_piece(&game.mailbox, mv);
move_parameters.add_captured_piece(&game.mailbox, mv);
move_parameters.add_promoted_piece(mv, game.current_player());
move_parameters.add_zobrist_hash(&game.hash);
move_parameters
}
pub fn build_null(game: &Game) -> Self {
let mut move_parameters = Self::new();
move_parameters.add_irreversible_parameters(&game.board.state);
move_parameters.add_zobrist_hash(&game.hash);
move_parameters
}
fn add_move(&mut self, mv: Move) {
pub const fn with_move(mut self, mv: Move) -> Self {
self.mv = Some(mv);
self
}
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 const fn with_castling_ability(mut self, castling_ability: [Castle; 2]) -> Self {
self.castling_ability = Some(castling_ability);
self
}
fn add_moving_piece(&mut self, mailbox: &Mailbox, mv: &Move) {
pub const fn with_en_passant_square(mut self, en_passant_square: Option<usize>) -> Self {
self.en_passant_square = en_passant_square;
self
}
pub const fn with_halfmove_clock(mut self, halfmove_clock: u8) -> Self {
self.halfmove_clock = Some(halfmove_clock);
self
}
pub const fn with_moving_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
self.moving_piece = mailbox.piece_at(mv.src());
self
}
fn add_captured_piece(&mut self, mailbox: &Mailbox, mv: &Move) {
pub fn with_captured_piece(mut self, mailbox: &Mailbox, mv: &Move) -> Self {
if let MoveType::Capture
| MoveType::PromotionCaptureKnight
| MoveType::PromotionCaptureBishop
@@ -107,21 +84,18 @@ impl MoveParameters {
{
self.captured_piece = mailbox.piece_at(mv.dst())
}
self
}
fn add_promoted_piece(&mut self, mv: &Move, color: Color) {
pub fn with_promoted_piece(mut self, mv: &Move, color: Color) -> Self {
if mv.is_promotion() {
self.promoted_piece = Some((mv.promotion_type().into_piece_type(), color));
}
self
}
fn add_zobrist_hash(&mut self, zobrist_hash: &ZobristHash) {
self.zobrist_hash = Some(zobrist_hash.to_owned())
}
}
impl Default for MoveParameters {
fn default() -> Self {
Self::new()
pub fn with_zobrist_hash(mut self, zobrist_hash: &ZobristHash) -> Self {
self.zobrist_hash = Some(zobrist_hash.to_owned());
self
}
}

View File

@@ -6,9 +6,7 @@ use super::{
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Mailbox {
pub mailbox: [Option<(PieceType, Color)>; 64],
}
pub struct Mailbox([Option<(PieceType, Color)>; 64]);
impl Mailbox {
pub fn from_board(board: &Board) -> Self {
@@ -22,15 +20,15 @@ impl Mailbox {
});
}
Self { mailbox }
Self(mailbox)
}
pub fn set_piece_at(&mut self, square: usize, piece: Option<(PieceType, Color)>) {
self.mailbox[square] = piece;
self.0[square] = piece;
}
pub const fn piece_at(&self, square: usize) -> Option<(PieceType, Color)> {
self.mailbox[square]
self.0[square]
}
}
@@ -68,7 +66,7 @@ mod tests {
Some((PieceType::King, Color::Black)), Some((PieceType::Bishop, Color::Black)), Some((PieceType::Knight, Color::Black)), Some((PieceType::Rook, Color::Black)),
];
assert_eq!(expected, mailbox.mailbox);
assert_eq!(expected, mailbox.0);
Ok(())
}