use super::Bitboard; use crate::utils::static_assert; /// An enum representing a singular rank on a chess board (i.e: the rows). #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Rank { First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, } impl Rank { const ALL: [Rank; 8] = [ Rank::First, Rank::Second, Rank::Third, Rank::Fourth, Rank::Fifth, Rank::Sixth, Rank::Seventh, Rank::Eighth, ]; /// Iterate over all ranks in order. pub fn iter() -> impl Iterator { Self::ALL.iter().cloned() } /// Convert from a rank index into a [Rank] type. #[inline(always)] pub fn from_index(index: usize) -> Self { assert!(index < 8); // SAFETY: we know the value is in-bounds unsafe { Self::from_index_unchecked(index) } } /// Convert from a rank index into a [Rank] type, no bounds checking. #[inline(always)] pub unsafe fn from_index_unchecked(index: usize) -> Self { std::mem::transmute(index as u8) } /// Return the index of a given [Rank]. #[inline(always)] pub fn index(self) -> usize { self as usize } /// Return the [Rank] one-row up, as seen from white's perspective. Wraps around the board. pub fn up(self) -> Self { // SAFETY: we know the value is in-bounds, through masking unsafe { Self::from_index_unchecked(self.index().wrapping_add(1) & 7) } } /// Return the [Rank] one-row down, as seen from white's perspective. Wraps around the board. pub fn down(self) -> Self { // SAFETY: we know the value is in-bounds, through masking unsafe { Self::from_index_unchecked(self.index().wrapping_sub(1) & 7) } } /// Turn a [Rank] into a [Bitboard] of all squares in that rank. #[inline(always)] pub fn into_bitboard(self) -> Bitboard { // SAFETY: we know the value is in-bounds unsafe { *Bitboard::RANKS.get_unchecked(self.index()) } } } // Ensure that niche-optimization is in effect. static_assert!(std::mem::size_of::>() == std::mem::size_of::()); #[cfg(test)] mod test { use super::*; #[test] fn from_index() { assert_eq!(Rank::from_index(0), Rank::First); assert_eq!(Rank::from_index(1), Rank::Second); assert_eq!(Rank::from_index(7), Rank::Eighth); } #[test] fn index() { assert_eq!(Rank::First.index(), 0); assert_eq!(Rank::Second.index(), 1); assert_eq!(Rank::Eighth.index(), 7); } #[test] fn up() { assert_eq!(Rank::First.up(), Rank::Second); assert_eq!(Rank::Second.up(), Rank::Third); assert_eq!(Rank::Eighth.up(), Rank::First); } #[test] fn down() { assert_eq!(Rank::First.down(), Rank::Eighth); assert_eq!(Rank::Second.down(), Rank::First); assert_eq!(Rank::Eighth.down(), Rank::Seventh); } #[test] fn into_bitboard() { assert_eq!(Rank::First.into_bitboard(), Bitboard::RANKS[0]); assert_eq!(Rank::Second.into_bitboard(), Bitboard::RANKS[1]); assert_eq!(Rank::Eighth.into_bitboard(), Bitboard::RANKS[7]); } }