Rename 'ValidationError'

This is a better, clearer name.
This commit is contained in:
Bruno BELANYI 2024-04-03 20:15:17 +01:00
parent 6f161d067d
commit 7d9c5edb99
4 changed files with 45 additions and 45 deletions

View file

@ -1,4 +1,4 @@
use crate::board::{Bitboard, CastleRights, ChessBoard, Color, InvalidError, Piece, Square}; use crate::board::{Bitboard, CastleRights, ChessBoard, Color, Piece, Square, ValidationError};
/// Build a [ChessBoard] one piece at a time. /// Build a [ChessBoard] one piece at a time.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@ -80,7 +80,7 @@ impl std::ops::IndexMut<Square> for ChessBoardBuilder {
} }
impl TryFrom<ChessBoardBuilder> for ChessBoard { impl TryFrom<ChessBoardBuilder> for ChessBoard {
type Error = InvalidError; type Error = ValidationError;
fn try_from(builder: ChessBoardBuilder) -> Result<Self, Self::Error> { fn try_from(builder: ChessBoardBuilder) -> Result<Self, Self::Error> {
let mut piece_occupancy: [Bitboard; Piece::NUM_VARIANTS] = Default::default(); let mut piece_occupancy: [Bitboard; Piece::NUM_VARIANTS] = Default::default();

View file

@ -1,6 +1,6 @@
/// A singular type for all errors that could happen during [ChessBoard::is_valid]. /// A singular type for all errors that could happen during [ChessBoard::is_valid].
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum InvalidError { pub enum ValidationError {
/// Too many pieces. /// Too many pieces.
TooManyPieces, TooManyPieces,
/// Missing king. /// Missing king.
@ -27,7 +27,7 @@ pub enum InvalidError {
IncoherentPlieCount, IncoherentPlieCount,
} }
impl std::fmt::Display for InvalidError { impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let error_msg = match self { let error_msg = match self {
Self::TooManyPieces => "Too many pieces.", Self::TooManyPieces => "Too many pieces.",
@ -53,4 +53,4 @@ impl std::fmt::Display for InvalidError {
} }
} }
impl std::error::Error for InvalidError {} impl std::error::Error for ValidationError {}

View file

@ -206,16 +206,16 @@ impl ChessBoard {
self.validate().is_ok() self.validate().is_ok()
} }
/// Validate the state of the board. Return Err([InvalidError]) if an issue is found. /// Validate the state of the board. Return Err([ValidationError]) if an issue is found.
pub fn validate(&self) -> Result<(), InvalidError> { pub fn validate(&self) -> Result<(), ValidationError> {
// The current plie count should be odd on white's turn, and vice-versa. // The current plie count should be odd on white's turn, and vice-versa.
if self.total_plies() % 2 != self.current_player().index() as u32 { if self.total_plies() % 2 != self.current_player().index() as u32 {
return Err(InvalidError::IncoherentPlieCount); return Err(ValidationError::IncoherentPlieCount);
} }
// Make sure the clocks are in agreement. // Make sure the clocks are in agreement.
if self.half_move_clock() > self.total_plies() { if self.half_move_clock() > self.total_plies() {
return Err(InvalidError::HalfMoveClockTooHigh); return Err(ValidationError::HalfMoveClockTooHigh);
} }
// Don't overlap pieces. // Don't overlap pieces.
@ -224,7 +224,7 @@ impl ChessBoard {
for other in Piece::iter() { for other in Piece::iter() {
if piece != other { if piece != other {
if !(self.piece_occupancy(piece) & self.piece_occupancy(other)).is_empty() { if !(self.piece_occupancy(piece) & self.piece_occupancy(other)).is_empty() {
return Err(InvalidError::OverlappingPieces); return Err(ValidationError::OverlappingPieces);
} }
} }
} }
@ -232,7 +232,7 @@ impl ChessBoard {
// Don't overlap colors. // Don't overlap colors.
if !(self.color_occupancy(Color::White) & self.color_occupancy(Color::Black)).is_empty() { if !(self.color_occupancy(Color::White) & self.color_occupancy(Color::Black)).is_empty() {
return Err(InvalidError::OverlappingColors); return Err(ValidationError::OverlappingColors);
} }
// Calculate the union of all pieces. // Calculate the union of all pieces.
@ -241,12 +241,12 @@ impl ChessBoard {
// Ensure that the pre-computed version is accurate. // Ensure that the pre-computed version is accurate.
if combined != self.combined_occupancy() { if combined != self.combined_occupancy() {
return Err(InvalidError::ErroneousCombinedOccupancy); return Err(ValidationError::ErroneousCombinedOccupancy);
} }
// Ensure that all pieces belong to a color, and no color has pieces that don't exist. // Ensure that all pieces belong to a color, and no color has pieces that don't exist.
if combined != (self.color_occupancy(Color::White) | self.color_occupancy(Color::Black)) { if combined != (self.color_occupancy(Color::White) | self.color_occupancy(Color::Black)) {
return Err(InvalidError::ErroneousCombinedOccupancy); return Err(ValidationError::ErroneousCombinedOccupancy);
} }
for color in Color::iter() { for color in Color::iter() {
@ -260,18 +260,18 @@ impl ChessBoard {
_ => count <= 10, _ => count <= 10,
}; };
if !possible { if !possible {
return Err(InvalidError::TooManyPieces); return Err(ValidationError::TooManyPieces);
} }
} }
// Check that we have a king // Check that we have a king
if self.occupancy(Piece::King, color).count() != 1 { if self.occupancy(Piece::King, color).count() != 1 {
return Err(InvalidError::MissingKing); return Err(ValidationError::MissingKing);
} }
// Check that don't have too many pieces in total // Check that don't have too many pieces in total
if self.color_occupancy(color).count() > 16 { if self.color_occupancy(color).count() > 16 {
return Err(InvalidError::TooManyPieces); return Err(ValidationError::TooManyPieces);
} }
} }
@ -280,7 +280,7 @@ impl ChessBoard {
& (Rank::First.into_bitboard() | Rank::Eighth.into_bitboard())) & (Rank::First.into_bitboard() | Rank::Eighth.into_bitboard()))
.is_empty() .is_empty()
{ {
return Err(InvalidError::InvalidPawnPosition); return Err(ValidationError::InvalidPawnPosition);
} }
// Verify that rooks and kings that are allowed to castle have not been moved. // Verify that rooks and kings that are allowed to castle have not been moved.
@ -296,14 +296,14 @@ impl ChessBoard {
let expected_rooks = castle_rights.unmoved_rooks(color); let expected_rooks = castle_rights.unmoved_rooks(color);
// We must check the intersection, in case there are more than 2 rooks on the board. // We must check the intersection, in case there are more than 2 rooks on the board.
if (expected_rooks & actual_rooks) != expected_rooks { if (expected_rooks & actual_rooks) != expected_rooks {
return Err(InvalidError::InvalidCastlingRights); return Err(ValidationError::InvalidCastlingRights);
} }
let actual_king = self.occupancy(Piece::King, color); let actual_king = self.occupancy(Piece::King, color);
let expected_king = Square::new(File::E, color.first_rank()); let expected_king = Square::new(File::E, color.first_rank());
// We have checked that there is exactly one king, no need for intersecting the sets. // We have checked that there is exactly one king, no need for intersecting the sets.
if actual_king != expected_king.into_bitboard() { if actual_king != expected_king.into_bitboard() {
return Err(InvalidError::InvalidCastlingRights); return Err(ValidationError::InvalidCastlingRights);
} }
} }
@ -311,14 +311,14 @@ impl ChessBoard {
if let Some(square) = self.en_passant() { if let Some(square) = self.en_passant() {
// Must be empty // Must be empty
if !(self.combined_occupancy() & square).is_empty() { if !(self.combined_occupancy() & square).is_empty() {
return Err(InvalidError::InvalidEnPassant); return Err(ValidationError::InvalidEnPassant);
} }
let opponent = !self.current_player(); let opponent = !self.current_player();
// Must be on the opponent's third rank // Must be on the opponent's third rank
if (square & opponent.third_rank().into_bitboard()).is_empty() { if (square & opponent.third_rank().into_bitboard()).is_empty() {
return Err(InvalidError::InvalidEnPassant); return Err(ValidationError::InvalidEnPassant);
} }
// Must be behind a pawn // Must be behind a pawn
@ -328,7 +328,7 @@ impl ChessBoard {
.backward_direction() .backward_direction()
.move_board(square.into_bitboard()); .move_board(square.into_bitboard());
if (opponent_pawns & double_pushed_pawn).is_empty() { if (opponent_pawns & double_pushed_pawn).is_empty() {
return Err(InvalidError::InvalidEnPassant); return Err(ValidationError::InvalidEnPassant);
} }
} }
@ -337,12 +337,12 @@ impl ChessBoard {
let black_king = self.occupancy(Piece::King, Color::Black); let black_king = self.occupancy(Piece::King, Color::Black);
// Unwrap is fine, we already checked that there is exactly one king of each color // Unwrap is fine, we already checked that there is exactly one king of each color
if !(movegen::king_moves(white_king.try_into().unwrap()) & black_king).is_empty() { if !(movegen::king_moves(white_king.try_into().unwrap()) & black_king).is_empty() {
return Err(InvalidError::NeighbouringKings); return Err(ValidationError::NeighbouringKings);
} }
// Check that the opponent is not currently in check. // Check that the opponent is not currently in check.
if !self.compute_checkers(!self.current_player()).is_empty() { if !self.compute_checkers(!self.current_player()).is_empty() {
return Err(InvalidError::OpponentInCheck); return Err(ValidationError::OpponentInCheck);
} }
Ok(()) Ok(())
@ -445,7 +445,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
position.validate().err().unwrap(), position.validate().err().unwrap(),
InvalidError::IncoherentPlieCount, ValidationError::IncoherentPlieCount,
); );
} }
@ -458,7 +458,7 @@ mod test {
builder.with_half_move_clock(10); builder.with_half_move_clock(10);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::HalfMoveClockTooHigh); assert_eq!(res.err().unwrap(), ValidationError::HalfMoveClockTooHigh);
} }
#[test] #[test]
@ -473,7 +473,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
position.validate().err().unwrap(), position.validate().err().unwrap(),
InvalidError::OverlappingPieces, ValidationError::OverlappingPieces,
); );
} }
@ -489,7 +489,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
position.validate().err().unwrap(), position.validate().err().unwrap(),
InvalidError::OverlappingColors, ValidationError::OverlappingColors,
); );
} }
@ -505,7 +505,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
position.validate().err().unwrap(), position.validate().err().unwrap(),
InvalidError::ErroneousCombinedOccupancy, ValidationError::ErroneousCombinedOccupancy,
); );
} }
@ -521,7 +521,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
position.validate().err().unwrap(), position.validate().err().unwrap(),
InvalidError::ErroneousCombinedOccupancy, ValidationError::ErroneousCombinedOccupancy,
); );
} }
@ -535,7 +535,7 @@ mod test {
builder[Square::E8] = Some((Piece::King, Color::Black)); builder[Square::E8] = Some((Piece::King, Color::Black));
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::TooManyPieces); assert_eq!(res.err().unwrap(), ValidationError::TooManyPieces);
} }
#[test] #[test]
@ -547,7 +547,7 @@ mod test {
builder.with_castle_rights(CastleRights::BothSides, Color::White); builder.with_castle_rights(CastleRights::BothSides, Color::White);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidCastlingRights); assert_eq!(res.err().unwrap(), ValidationError::InvalidCastlingRights);
} }
#[test] #[test]
@ -563,7 +563,7 @@ mod test {
builder.with_castle_rights(CastleRights::BothSides, Color::White); builder.with_castle_rights(CastleRights::BothSides, Color::White);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidCastlingRights); assert_eq!(res.err().unwrap(), ValidationError::InvalidCastlingRights);
} }
#[test] #[test]
@ -587,7 +587,7 @@ mod test {
builder.with_en_passant(Square::A6); builder.with_en_passant(Square::A6);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidEnPassant); assert_eq!(res.err().unwrap(), ValidationError::InvalidEnPassant);
} }
#[test] #[test]
@ -600,7 +600,7 @@ mod test {
builder.with_en_passant(Square::A6); builder.with_en_passant(Square::A6);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidEnPassant); assert_eq!(res.err().unwrap(), ValidationError::InvalidEnPassant);
} }
#[test] #[test]
@ -613,7 +613,7 @@ mod test {
builder.with_en_passant(Square::A5); builder.with_en_passant(Square::A5);
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidEnPassant); assert_eq!(res.err().unwrap(), ValidationError::InvalidEnPassant);
} }
#[test] #[test]
@ -624,7 +624,7 @@ mod test {
builder[Square::E2] = Some((Piece::King, Color::Black)); builder[Square::E2] = Some((Piece::King, Color::Black));
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::NeighbouringKings); assert_eq!(res.err().unwrap(), ValidationError::NeighbouringKings);
} }
#[test] #[test]
@ -636,7 +636,7 @@ mod test {
builder[Square::E8] = Some((Piece::King, Color::Black)); builder[Square::E8] = Some((Piece::King, Color::Black));
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::OpponentInCheck); assert_eq!(res.err().unwrap(), ValidationError::OpponentInCheck);
} }
#[test] #[test]
@ -648,7 +648,7 @@ mod test {
builder[Square::H8] = Some((Piece::King, Color::Black)); builder[Square::H8] = Some((Piece::King, Color::Black));
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::InvalidPawnPosition); assert_eq!(res.err().unwrap(), ValidationError::InvalidPawnPosition);
} }
#[test] #[test]
@ -665,7 +665,7 @@ mod test {
} }
TryInto::<ChessBoard>::try_into(builder) TryInto::<ChessBoard>::try_into(builder)
}; };
assert_eq!(res.err().unwrap(), InvalidError::TooManyPieces); assert_eq!(res.err().unwrap(), ValidationError::TooManyPieces);
} }
#[test] #[test]

View file

@ -1,5 +1,5 @@
use crate::board::{ use crate::board::{
CastleRights, ChessBoard, ChessBoardBuilder, Color, File, InvalidError, Piece, Rank, Square, CastleRights, ChessBoard, ChessBoardBuilder, Color, File, Piece, Rank, Square, ValidationError,
}; };
/// A trait to mark items that can be converted from a FEN input. /// A trait to mark items that can be converted from a FEN input.
@ -15,7 +15,7 @@ pub enum FenError {
/// Invalid FEN input. /// Invalid FEN input.
InvalidFen, InvalidFen,
/// Invalid chess position. /// Invalid chess position.
InvalidPosition(InvalidError), InvalidPosition(ValidationError),
} }
impl std::fmt::Display for FenError { impl std::fmt::Display for FenError {
@ -29,9 +29,9 @@ impl std::fmt::Display for FenError {
impl std::error::Error for FenError {} impl std::error::Error for FenError {}
/// Allow converting a [InvalidError] into [FenError], for use with the '?' operator. /// Allow converting a [ValidationError] into [FenError], for use with the '?' operator.
impl From<InvalidError> for FenError { impl From<ValidationError> for FenError {
fn from(err: InvalidError) -> Self { fn from(err: ValidationError) -> Self {
Self::InvalidPosition(err) Self::InvalidPosition(err)
} }
} }