// Eryn Wells use super::BitScanner; use crate::Square; use std::fmt; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub(crate) struct BitBoard(pub(super) u64); impl BitBoard { pub fn empty() -> BitBoard { BitBoard(0) } pub fn new(bits: u64) -> BitBoard { BitBoard(bits) } pub fn rank(rank: u8) -> BitBoard { BitBoard(0xFF).shift_north(rank) } pub fn is_empty(&self) -> bool { self.0 == 0 } pub fn has_piece_at(&self, sq: &Square) -> bool { (self.0 & (1 << sq.index())) > 0 } pub fn place_piece_at(&mut self, sq: &Square) { self.0 |= 1 << sq.index() } fn remove_piece_at(&mut self, sq: &Square) { self.0 &= !(1 << sq.index()) } } impl BitBoard { pub(crate) fn occupied_squares(&self) -> impl Iterator { BitScanner::new(self.0) .map(|x| u8::try_from(x)) .take_while(|x| x.is_ok()) .map(|x| Square::from_index_unsafe(x.unwrap())) } } impl fmt::Binary for BitBoard { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Delegate to u64's implementation of Binary. fmt::Binary::fmt(&self.0, f) } } impl fmt::LowerHex for BitBoard { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Delegate to u64's implementation of LowerHex. fmt::LowerHex::fmt(&self.0, f) } } impl fmt::UpperHex for BitBoard { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Delegate to u64's implementation of UpperHex. fmt::UpperHex::fmt(&self.0, f) } } impl fmt::Debug for BitBoard { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.debug_tuple("BitBoard") .field(&format_args!("{:064b}", self.0)) .finish() } } macro_rules! infix_op { ($trait_type:ident, $func_name:ident, $left_type:ty, $right_type:ty, $op:tt) => { impl $trait_type<$right_type> for $left_type { type Output = BitBoard; #[inline] fn $func_name(self, rhs: $right_type) -> Self::Output { BitBoard(self.0 $op rhs.0) } } }; } macro_rules! assign_op { ($trait_type:ident, $func_name:ident, $left_type:ty, $op:tt) => { impl $trait_type for $left_type { #[inline] fn $func_name(&mut self, rhs: Self) { self.0 $op rhs.0 } } }; } infix_op!(BitAnd, bitand, BitBoard, BitBoard, &); infix_op!(BitAnd, bitand, &BitBoard, BitBoard, &); infix_op!(BitAnd, bitand, BitBoard, &BitBoard, &); infix_op!(BitAnd, bitand, &BitBoard, &BitBoard, &); assign_op!(BitAndAssign, bitand_assign, BitBoard, &=); assign_op!(BitOrAssign, bitor_assign, BitBoard, |=); infix_op!(BitOr, bitor, BitBoard, BitBoard, |); infix_op!(BitOr, bitor, &BitBoard, BitBoard, |); infix_op!(BitOr, bitor, BitBoard, &BitBoard, |); infix_op!(BitOr, bitor, &BitBoard, &BitBoard, |); impl Not for BitBoard { type Output = BitBoard; #[inline] fn not(self) -> Self::Output { BitBoard(!self.0) } } impl Not for &BitBoard { type Output = BitBoard; #[inline] fn not(self) -> Self::Output { BitBoard(!self.0) } } #[cfg(test)] mod tests { use super::*; use crate::Square; #[test] fn rank() { assert_eq!(BitBoard::rank(0).0, 0xFF, "Rank 1"); assert_eq!(BitBoard::rank(1).0, 0xFF00, "Rank 2"); assert_eq!(BitBoard::rank(2).0, 0xFF0000, "Rank 3"); assert_eq!(BitBoard::rank(3).0, 0xFF000000, "Rank 4"); assert_eq!(BitBoard::rank(4).0, 0xFF00000000, "Rank 5"); assert_eq!(BitBoard::rank(5).0, 0xFF0000000000, "Rank 6"); assert_eq!(BitBoard::rank(6).0, 0xFF000000000000, "Rank 7"); assert_eq!(BitBoard::rank(7).0, 0xFF00000000000000, "Rank 8"); } #[test] fn is_empty() { assert!(BitBoard(0).is_empty()); assert!(!BitBoard(0xFF).is_empty()); } #[test] fn has_piece_at() { let bb = BitBoard(0b1001100); let c1 = Square::from_algebraic_str("c1").expect("Unable to get square for 'c1'"); assert!(bb.has_piece_at(&c1)); let b1 = Square::from_algebraic_str("b1").expect("Unable to get square for 'b1'"); assert!(!bb.has_piece_at(&b1)); } #[test] fn place_piece_at() { let sq = Square::from_index(34).expect("Invalid square index"); let mut bb = BitBoard(0b1001100); bb.place_piece_at(&sq); assert!(bb.has_piece_at(&sq)); } #[test] fn remove_piece_at() { let sq = Square::from_index(2).expect("Invalid square index"); let mut bb = BitBoard(0b1001100); bb.remove_piece_at(&sq); assert!(!bb.has_piece_at(&sq)); } #[test] fn pieces() { let bb = BitBoard(0x1001_1010); // e4 let mut occupied_squares = bb.occupied_squares(); assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(28))); assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(16))); assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(12))); assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(4))); assert_eq!(occupied_squares.next(), None); } }