diff --git a/src/board/bitboard/error.rs b/src/board/bitboard/error.rs new file mode 100644 index 0000000..c631482 --- /dev/null +++ b/src/board/bitboard/error.rs @@ -0,0 +1,19 @@ +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum IntoSquareError { + /// The board is empty. + EmptyBoard, + /// The board contains more than one square. + TooManySquares, +} + +impl std::fmt::Display for IntoSquareError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let error_msg = match self { + Self::EmptyBoard => "The board is empty", + Self::TooManySquares => "The board contains more than one square", + }; + write!(f, "{}", error_msg) + } +} + +impl std::error::Error for IntoSquareError {} diff --git a/src/board/bitboard/mod.rs b/src/board/bitboard/mod.rs index e186a07..b0ec90a 100644 --- a/src/board/bitboard/mod.rs +++ b/src/board/bitboard/mod.rs @@ -1,6 +1,8 @@ use super::Square; use crate::utils::static_assert; +mod error; +use error::*; mod iterator; use iterator::*; mod superset; @@ -102,6 +104,21 @@ impl IntoIterator for Bitboard { } } +/// If the given [Bitboard] is a singleton piece on a board, return the [Square] that it is +/// occupying. Otherwise return `None`. +impl TryInto for Bitboard { + type Error = IntoSquareError; + + fn try_into(self) -> Result { + let index = match self.count() { + 1 => self.0.trailing_zeros() as usize, + 0 => return Err(IntoSquareError::EmptyBoard), + _ => return Err(IntoSquareError::TooManySquares), + }; + Ok(Square::from_index(index)) + } +} + /// Treat bitboard as a set of squares, shift each square's index left by the amount given. impl std::ops::Shl for Bitboard { type Output = Bitboard; @@ -461,4 +478,23 @@ mod test { 1 << 8 ); } + + #[test] + fn into_square() { + for square in Square::iter() { + assert_eq!(square.into_bitboard().try_into(), Ok(square)); + } + } + + #[test] + fn into_square_invalid() { + assert_eq!( + TryInto::::try_into(Bitboard::EMPTY), + Err(IntoSquareError::EmptyBoard) + ); + assert_eq!( + TryInto::::try_into(Square::A1 | Square::A2), + Err(IntoSquareError::TooManySquares) + ) + } }