2024-02-03 15:17:02 -08:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
2025-05-02 15:03:48 -07:00
|
|
|
mod parameters;
|
|
|
|
mod rights;
|
|
|
|
|
2025-05-19 16:50:30 -07:00
|
|
|
pub use parameters::Parameters;
|
2025-06-18 23:44:40 +00:00
|
|
|
pub use rights::{CastleRightsOption, Rights};
|
2025-05-21 10:08:59 -07:00
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
use crate::{Board, CastleParameters};
|
2025-06-18 23:44:40 +00:00
|
|
|
use chessfriend_core::{Color, Wing};
|
2025-05-21 10:08:59 -07:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
|
|
|
pub enum CastleEvaluationError {
|
|
|
|
#[error("{color} does not have the right to castle {wing}")]
|
|
|
|
NoRights { color: Color, wing: Wing },
|
|
|
|
#[error("no king")]
|
|
|
|
NoKing,
|
|
|
|
#[error("no rook")]
|
|
|
|
NoRook,
|
|
|
|
#[error("castling path is not clear")]
|
|
|
|
ObstructingPieces,
|
|
|
|
#[error("opposing pieces check castling path")]
|
|
|
|
CheckingPieces,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Board {
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
#[must_use]
|
|
|
|
pub fn castling_parameters(wing: Wing, color: Color) -> &'static CastleParameters {
|
|
|
|
&CastleParameters::BY_COLOR[color as usize][wing as usize]
|
|
|
|
}
|
|
|
|
|
2025-05-21 10:08:59 -07:00
|
|
|
/// Evaluates whether the active color can castle toward the given wing of the board in the
|
|
|
|
/// current position.
|
|
|
|
///
|
|
|
|
/// ## Errors
|
|
|
|
///
|
|
|
|
/// Returns an error indicating why the active color cannot castle.
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pub fn color_can_castle(
|
|
|
|
&self,
|
|
|
|
wing: Wing,
|
|
|
|
color: Option<Color>,
|
|
|
|
) -> Result<&'static CastleParameters, CastleEvaluationError> {
|
2025-05-21 10:08:59 -07:00
|
|
|
// TODO: Cache this result. It's expensive!
|
|
|
|
// TODO: Does this actually need to rely on internal state, i.e. active_color?
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let color = self.unwrap_color(color);
|
2025-05-21 10:08:59 -07:00
|
|
|
|
2025-06-18 23:44:40 +00:00
|
|
|
if !self.has_castling_right_unwrapped(color, wing.into()) {
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
return Err(CastleEvaluationError::NoRights { color, wing });
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let parameters = Self::castling_parameters(wing, color);
|
2025-05-21 10:08:59 -07:00
|
|
|
|
|
|
|
if self.castling_king(parameters.origin.king).is_none() {
|
|
|
|
return Err(CastleEvaluationError::NoKing);
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.castling_rook(parameters.origin.rook).is_none() {
|
|
|
|
return Err(CastleEvaluationError::NoRook);
|
|
|
|
}
|
|
|
|
|
|
|
|
// All squares must be clear.
|
|
|
|
let has_obstructing_pieces = (self.occupancy() & parameters.clear).is_populated();
|
|
|
|
if has_obstructing_pieces {
|
|
|
|
return Err(CastleEvaluationError::ObstructingPieces);
|
|
|
|
}
|
|
|
|
|
|
|
|
// King cannot pass through check.
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let opposing_sight = self.opposing_sight(color);
|
2025-05-21 10:08:59 -07:00
|
|
|
let opposing_pieces_can_see_castling_path =
|
|
|
|
(parameters.check & opposing_sight).is_populated();
|
|
|
|
if opposing_pieces_can_see_castling_path {
|
|
|
|
return Err(CastleEvaluationError::CheckingPieces);
|
|
|
|
}
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
Ok(parameters)
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
2025-06-18 23:44:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Board {
|
|
|
|
#[must_use]
|
|
|
|
pub fn has_castling_right(&self, color: Option<Color>, wing: Wing) -> bool {
|
|
|
|
self.has_castling_right_unwrapped(self.unwrap_color(color), wing)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
|
|
|
pub fn has_castling_right_active(&self, wing: Wing) -> bool {
|
|
|
|
self.has_castling_right_unwrapped(self.active_color(), wing)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
|
|
|
pub fn has_castling_right_unwrapped(&self, color: Color, wing: Wing) -> bool {
|
|
|
|
self.castling_rights().get(color, wing.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Board {
|
|
|
|
pub fn grant_castling_rights(&mut self, color: Option<Color>, rights: CastleRightsOption) {
|
|
|
|
let color = self.unwrap_color(color);
|
|
|
|
self.grant_castling_rights_unwrapped(color, rights);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn grant_castling_rights_active(&mut self, rights: CastleRightsOption) {
|
|
|
|
self.grant_castling_rights_unwrapped(self.active_color(), rights);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn grant_castling_rights_unwrapped(&mut self, color: Color, rights: CastleRightsOption) {
|
|
|
|
let old_rights = *self.castling_rights();
|
|
|
|
self.castling_rights_mut().grant(color, rights);
|
|
|
|
self.update_zobrist_hash_castling_rights(old_rights);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Board {
|
|
|
|
pub fn revoke_all_castling_rights(&mut self) {
|
|
|
|
self.castling_rights_mut().revoke_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn revoke_castling_rights(&mut self, color: Option<Color>, rights: CastleRightsOption) {
|
|
|
|
let color = self.unwrap_color(color);
|
|
|
|
self.revoke_castling_rights_unwrapped(color, rights);
|
|
|
|
}
|
2025-05-21 10:08:59 -07:00
|
|
|
|
2025-06-18 23:44:40 +00:00
|
|
|
pub fn revoke_castling_rights_active(&mut self, rights: CastleRightsOption) {
|
|
|
|
self.revoke_castling_rights_unwrapped(self.active_color(), rights);
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
|
2025-06-18 23:44:40 +00:00
|
|
|
pub fn revoke_castling_rights_unwrapped(&mut self, color: Color, rights: CastleRightsOption) {
|
|
|
|
let old_rights = *self.castling_rights();
|
|
|
|
self.castling_rights_mut().revoke(color, rights);
|
|
|
|
self.update_zobrist_hash_castling_rights(old_rights);
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::test_board;
|
2025-06-17 08:28:39 -07:00
|
|
|
use chessfriend_core::{Color, Wing, piece};
|
2025-05-21 10:08:59 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn king_on_starting_square_can_castle() {
|
2025-06-03 20:25:53 -07:00
|
|
|
let board = test_board!(
|
2025-05-21 10:08:59 -07:00
|
|
|
White King on E1,
|
|
|
|
White Rook on A1,
|
|
|
|
White Rook on H1
|
|
|
|
);
|
|
|
|
|
2025-06-18 23:44:40 +00:00
|
|
|
assert!(board.has_castling_right_unwrapped(Color::White, Wing::KingSide));
|
|
|
|
assert!(board.has_castling_right_unwrapped(Color::White, Wing::QueenSide));
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn king_for_castle() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on H1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let kingside_parameters = Board::castling_parameters(Wing::KingSide, Color::White);
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(
|
|
|
|
pos.castling_king(kingside_parameters.origin.king),
|
|
|
|
Some(piece!(White King))
|
|
|
|
);
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let queenside_parameters = Board::castling_parameters(Wing::QueenSide, Color::White);
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(
|
|
|
|
pos.castling_king(queenside_parameters.origin.king),
|
|
|
|
Some(piece!(White King))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rook_for_castle() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on H1,
|
|
|
|
];
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let kingside_parameters = Board::castling_parameters(Wing::KingSide, Color::White);
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(
|
|
|
|
pos.castling_rook(kingside_parameters.origin.rook),
|
|
|
|
Some(piece!(White Rook))
|
|
|
|
);
|
|
|
|
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
let queenside_parameters = Board::castling_parameters(Wing::QueenSide, Color::White);
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(
|
|
|
|
pos.castling_rook(queenside_parameters.origin.rook),
|
|
|
|
Some(piece!(White Rook))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
fn white_can_castle() -> Result<(), CastleEvaluationError> {
|
2025-05-21 10:08:59 -07:00
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on H1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::KingSide, None)?;
|
|
|
|
pos.color_can_castle(Wing::QueenSide, None)?;
|
|
|
|
|
|
|
|
Ok(())
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn white_cannot_castle_missing_king() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E2,
|
|
|
|
White Rook on H1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::KingSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::NoKing)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::QueenSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::NoKing)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn white_cannot_castle_missing_rook() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::KingSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::NoRook)
|
|
|
|
);
|
|
|
|
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on H1,
|
|
|
|
];
|
|
|
|
|
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::QueenSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::NoRook)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn white_cannot_castle_obstructing_piece() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Bishop on F1,
|
|
|
|
White Rook on H1,
|
|
|
|
White Rook on A1,
|
|
|
|
];
|
|
|
|
|
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::KingSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::ObstructingPieces)
|
|
|
|
);
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
assert!(pos.color_can_castle(Wing::QueenSide, None).is_ok());
|
2025-05-21 10:08:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn white_cannot_castle_checking_pieces() {
|
|
|
|
let pos = test_board![
|
|
|
|
White King on E1,
|
|
|
|
White Rook on H1,
|
|
|
|
White Rook on A1,
|
|
|
|
Black Queen on C6,
|
|
|
|
];
|
|
|
|
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
assert!(pos.color_can_castle(Wing::KingSide, None).is_ok());
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
pos.color_can_castle(Wing::QueenSide, None),
|
2025-05-21 10:08:59 -07:00
|
|
|
Err(CastleEvaluationError::CheckingPieces)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|