use super::Bitboard; use crate::utils::static_assert; /// An enum representing a singular file on a chess board (i.e: the columns). #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum File { A, B, C, D, E, F, G, H, } impl File { const ALL: [File; 8] = [ File::A, File::B, File::C, File::D, File::E, File::F, File::G, File::H, ]; /// Iterate over all files in order. pub fn iter() -> impl Iterator { Self::ALL.iter().cloned() } /// Convert from a file index into a [File] 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 file index into a [File] 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 [File]. #[inline(always)] pub fn index(self) -> usize { self as usize } /// Return the [File] to the left, as seen from white's perspective. Wraps around the board. pub fn left(self) -> Self { // SAFETY: we know the value is in-bounds, through masking unsafe { Self::from_index_unchecked(self.index().wrapping_sub(1) & 7) } } /// Return the [File] to the right, as seen from white's perspective. Wraps around the board. pub fn right(self) -> Self { // SAFETY: we know the value is in-bounds, through masking unsafe { Self::from_index_unchecked(self.index().wrapping_add(1) & 7) } } /// Turn a [File] into a [Bitboard] of all squares in that file. #[inline(always)] pub fn into_bitboard(self) -> Bitboard { // SAFETY: we know the value is in-bounds unsafe { *Bitboard::FILES.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!(File::from_index(0), File::A); assert_eq!(File::from_index(1), File::B); assert_eq!(File::from_index(7), File::H); } #[test] fn index() { assert_eq!(File::A.index(), 0); assert_eq!(File::B.index(), 1); assert_eq!(File::H.index(), 7); } #[test] fn left() { assert_eq!(File::A.left(), File::H); assert_eq!(File::B.left(), File::A); assert_eq!(File::H.left(), File::G); } #[test] fn right() { assert_eq!(File::A.right(), File::B); assert_eq!(File::B.right(), File::C); assert_eq!(File::H.right(), File::A); } #[test] fn into_bitboard() { assert_eq!(File::A.into_bitboard(), Bitboard::FILES[0]); assert_eq!(File::B.into_bitboard(), Bitboard::FILES[1]); assert_eq!(File::H.into_bitboard(), Bitboard::FILES[7]); } }