[moves] Revoke castling rights when King and Rook make moves of their starting squares

When the King moves, revoke all rights for the moving player. When the rook moves,
revoke castling rights for that side of the board, if it's moving off its starting
square.
This commit is contained in:
Eryn Wells 2025-06-17 16:18:48 -07:00
parent d73630c85e
commit c7b9544004

View file

@ -2,10 +2,10 @@
use crate::{Move, MoveRecord};
use chessfriend_board::{
castle::CastleEvaluationError, movement::Movement, Board, BoardProvider, PlacePieceError,
PlacePieceStrategy,
Board, BoardProvider, CastleParameters, PlacePieceError, PlacePieceStrategy,
castle::CastleEvaluationError, movement::Movement,
};
use chessfriend_core::{Color, Piece, Rank, Square, Wing};
use chessfriend_core::{Color, Piece, Rank, Shape, Square, Wing};
use thiserror::Error;
pub type MakeMoveResult = Result<MoveRecord, MakeMoveError>;
@ -83,6 +83,8 @@ trait MakeMoveInternal {
fn advance_board_state(
&mut self,
ply: &Move,
piece_moved: &Piece,
en_passant_target: Option<Square>,
half_move_clock: HalfMoveClock,
);
@ -151,7 +153,7 @@ impl<T: BoardProvider> MakeMoveInternal for T {
let record = MoveRecord::new(board, ply, None);
self.advance_board_state(None, HalfMoveClock::Advance);
self.advance_board_state(&ply, &piece, None, HalfMoveClock::Advance);
Ok(record)
}
@ -179,7 +181,12 @@ impl<T: BoardProvider> MakeMoveInternal for T {
_ => unreachable!(),
};
self.advance_board_state(Some(en_passant_target), HalfMoveClock::Advance);
self.advance_board_state(
&ply,
&piece,
Some(en_passant_target),
HalfMoveClock::Advance,
);
Ok(record)
}
@ -221,7 +228,7 @@ impl<T: BoardProvider> MakeMoveInternal for T {
let record = MoveRecord::new(board, ply, Some(captured_piece));
self.advance_board_state(None, HalfMoveClock::Reset);
self.advance_board_state(&ply, &piece, None, HalfMoveClock::Reset);
Ok(record)
}
@ -246,7 +253,7 @@ impl<T: BoardProvider> MakeMoveInternal for T {
board.revoke_castling_right_unwrapped(active_color, wing);
self.advance_board_state(None, HalfMoveClock::Advance);
self.advance_board_state(&ply, &king, None, HalfMoveClock::Advance);
Ok(record)
}
@ -280,28 +287,52 @@ impl<T: BoardProvider> MakeMoveInternal for T {
let record = MoveRecord::new(board, ply, None);
self.advance_board_state(None, HalfMoveClock::Reset);
self.advance_board_state(&ply, &piece, None, HalfMoveClock::Reset);
Ok(record)
}
fn advance_board_state(
&mut self,
ply: &Move,
piece_moved: &Piece,
en_passant_target: Option<Square>,
half_move_clock: HalfMoveClock,
) {
let board = self.board_mut();
match half_move_clock {
HalfMoveClock::Reset => board.half_move_clock = 0,
HalfMoveClock::Advance => board.half_move_clock += 1,
board.set_en_passant_target_option(en_passant_target);
match piece_moved.shape {
Shape::Rook => {
let origin = ply.origin_square();
if board.color_has_castling_right(None, Wing::KingSide) {
let kingside_parameters =
CastleParameters::get(board.active_color(), Wing::KingSide);
if origin == kingside_parameters.origin.rook {
board.revoke_castling_right(None, Wing::KingSide);
}
}
let queenside_parameters =
CastleParameters::get(board.active_color(), Wing::QueenSide);
if origin == queenside_parameters.origin.rook {
board.revoke_castling_right(None, Wing::QueenSide);
}
}
Shape::King => board.revoke_all_castling_rights(),
_ => {}
}
let previous_active_color = board.active_color();
let active_color = previous_active_color.next();
board.set_active_color(active_color);
board.set_en_passant_target_option(en_passant_target);
match half_move_clock {
HalfMoveClock::Reset => board.half_move_clock = 0,
HalfMoveClock::Advance => board.half_move_clock += 1,
}
if active_color == Color::White {
board.full_move_number += 1;