Compare commits

..

7 commits

Author SHA1 Message Date
1f52bb9346 Add tests for en-passant validation
All checks were successful
ci/woodpecker/push/check Pipeline was successful
2024-04-01 22:20:39 +01:00
385629b3a9 Validate en-passant square's rank in 'ChessBoard' 2024-04-01 22:20:39 +01:00
92a69ee741 Move FEN-related tests to its module 2024-04-01 22:20:39 +01:00
dbde58987c Move 'FromFen' for 'ChessBoard' into 'fen' module 2024-04-01 22:20:39 +01:00
8e0eabe187 Use 'ChessBoardBuilder' in 'FromFen'
This will allow taking this *out* of the module, now that we don't need
to reach into the internals of 'ChessBoard'.
2024-04-01 22:20:39 +01:00
5611a59449 Add 'From<InvalidError>' for 'FenError' 2024-04-01 22:20:39 +01:00
dfdc11b1fc Use 'ChessBoardBuilder' in validation tests
The various tests for overlapping can't be triggered with the builder
API, so those have stayed unchanged.
2024-04-01 22:20:39 +01:00
4 changed files with 11 additions and 32 deletions

View file

@ -9,9 +9,8 @@ pub struct ChessBoardBuilder {
castle_rights: [CastleRights; Color::NUM_VARIANTS],
en_passant: Option<Square>,
half_move_clock: u8,
total_plies: u32,
side: Color,
// 1-based, A turn is *two* half-moves (i.e: both players have played).
turn_count: u32,
}
impl ChessBoardBuilder {
@ -21,8 +20,8 @@ impl ChessBoardBuilder {
castle_rights: [CastleRights::NoSide; 2],
en_passant: Default::default(),
half_move_clock: Default::default(),
total_plies: Default::default(),
side: Color::White,
turn_count: 1,
}
}
@ -46,8 +45,8 @@ impl ChessBoardBuilder {
self
}
pub fn with_turn_count(&mut self, count: u32) -> &mut Self {
self.turn_count = count;
pub fn with_total_plies(&mut self, plies: u32) -> &mut Self {
self.total_plies = plies;
self
}
@ -91,8 +90,8 @@ impl TryFrom<ChessBoardBuilder> for ChessBoard {
castle_rights,
en_passant,
half_move_clock,
total_plies,
side,
turn_count,
} = builder;
for square in Square::iter() {
@ -104,8 +103,6 @@ impl TryFrom<ChessBoardBuilder> for ChessBoard {
combined_occupancy |= square;
}
let total_plies = (turn_count - 1) * 2 + if side == Color::White { 0 } else { 1 };
let board = ChessBoard {
piece_occupancy,
color_occupancy,
@ -149,7 +146,7 @@ mod test {
builder
.with_half_move_clock(board.half_move_clock())
.with_turn_count(board.total_plies() / 2 + 1)
.with_total_plies(board.total_plies())
.with_current_player(board.current_player());
builder

View file

@ -21,8 +21,6 @@ pub enum InvalidError {
OverlappingColors,
/// The pre-computed combined occupancy boards does not match the other boards.
ErroneousCombinedOccupancy,
/// Half-move clock is higher than total number of plies.
HalfMoveClockTooHigh,
}
impl std::fmt::Display for InvalidError {
@ -44,7 +42,6 @@ impl std::fmt::Display for InvalidError {
Self::ErroneousCombinedOccupancy => {
"The pre-computed combined occupancy boards does not match the other boards."
}
Self::HalfMoveClockTooHigh => "Half-move clock is higher than total number of plies.",
};
write!(f, "{}", error_msg)
}

View file

@ -208,11 +208,6 @@ impl ChessBoard {
/// Validate the state of the board. Return Err([InvalidError]) if an issue is found.
pub fn validate(&self) -> Result<(), InvalidError> {
// Make sure the clocks are in agreement.
if u32::from(self.half_move_clock()) > self.total_plies() {
return Err(InvalidError::HalfMoveClockTooHigh);
}
// Don't overlap pieces.
for piece in Piece::iter() {
#[allow(clippy::collapsible_if)]
@ -428,18 +423,6 @@ mod test {
assert!(default_position.is_valid());
}
#[test]
fn invalid_half_moves_clock() {
let res = {
let mut builder = ChessBoardBuilder::new();
builder[Square::E1] = Some((Piece::King, Color::White));
builder[Square::E8] = Some((Piece::King, Color::Black));
builder.with_half_move_clock(10);
TryInto::<ChessBoard>::try_into(builder)
};
assert_eq!(res.err().unwrap(), InvalidError::HalfMoveClockTooHigh);
}
#[test]
fn invalid_overlapping_pieces() {
let position = ChessBoard {
@ -696,10 +679,10 @@ mod test {
let mut builder = ChessBoardBuilder::new();
builder[Square::H1] = Some((Piece::King, Color::White));
builder[Square::H8] = Some((Piece::King, Color::Black));
for square in (File::B.into_bitboard() | File::C.into_bitboard()).into_iter() {
for square in (File::B.into_bitboard() | File::C.into_bitboard()) {
builder[square] = Some((Piece::Pawn, Color::White));
}
for square in (File::F.into_bitboard() | File::G.into_bitboard()).into_iter() {
for square in (File::F.into_bitboard() | File::G.into_bitboard()) {
builder[square] = Some((Piece::Pawn, Color::Black));
}
TryInto::<ChessBoard>::try_into(builder)

View file

@ -154,7 +154,9 @@ impl FromFen for ChessBoard {
let full_move_counter = full_move_counter
.parse::<u32>()
.map_err(|_| FenError::InvalidFen)?;
builder.with_turn_count(full_move_counter);
builder.with_total_plies(
(full_move_counter - 1) * 2 + if side == Color::White { 0 } else { 1 },
);
{
let mut rank: usize = 8;