diff --git a/board/src/bitboard/bitboard.rs b/board/src/bitboard/bitboard.rs index 7bcd3b8..c268ff7 100644 --- a/board/src/bitboard/bitboard.rs +++ b/board/src/bitboard/bitboard.rs @@ -42,24 +42,22 @@ impl BitBoard { moves_getter!(queen_moves); moves_getter!(king_moves); - pub fn from_square(sq: Square) -> BitBoard { - BitBoard(1 << sq.index()) - } - 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 has_piece_at(self, sq: Square) -> bool { + !(self & sq.into()).is_empty() } - pub fn place_piece_at(&mut self, sq: &Square) { - self.0 |= 1 << sq.index() + pub fn place_piece_at(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); + *self |= sq_bb } - fn remove_piece_at(&mut self, sq: &Square) { - self.0 &= !(1 << sq.index()) + fn remove_piece_at(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); + *self &= !sq_bb } } @@ -68,7 +66,13 @@ impl BitBoard { BitScanner::new(self.0) .map(|x| u8::try_from(x)) .take_while(|x| x.is_ok()) - .map(|x| Square::from_index_unsafe(x.unwrap())) + .map(|x| Square::from_index(x.unwrap() as usize)) + } +} + +impl From for BitBoard { + fn from(value: Square) -> Self { + BitBoard(1 << value as u64) } } @@ -125,41 +129,35 @@ impl fmt::Debug for BitBoard { } macro_rules! infix_op { - ($trait_type:ident, $func_name:ident, $left_type:ty, $right_type:ty, $op:tt) => { + ($trait_type:ident, $func_name:ident, $left_type:ty, $right_type:ty) => { 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) + BitBoard($trait_type::$func_name(self.0, rhs.0)) } } }; } macro_rules! assign_op { - ($trait_type:ident, $func_name:ident, $left_type:ty, $op:tt) => { + ($trait_type:ident, $func_name:ident, $left_type:ty) => { impl $trait_type for $left_type { #[inline] fn $func_name(&mut self, rhs: Self) { - self.0 $op rhs.0 + $trait_type::$func_name(&mut self.0, 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, &); +infix_op!(BitAnd, bitand, BitBoard, BitBoard); -assign_op!(BitAndAssign, bitand_assign, BitBoard, &=); -assign_op!(BitOrAssign, bitor_assign, 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, |); +infix_op!(BitOr, bitor, BitBoard, BitBoard); impl Not for BitBoard { type Output = BitBoard; @@ -212,41 +210,44 @@ mod tests { #[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)); + assert!(bb.has_piece_at(Square::C1)); + assert!(!bb.has_piece_at(Square::B1)); } #[test] fn place_piece_at() { - let sq = Square::from_index(34).expect("Invalid square index"); - + let sq = Square::E4; let mut bb = BitBoard(0b1001100); - bb.place_piece_at(&sq); - assert!(bb.has_piece_at(&sq)); + 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 sq = Square::A3; let mut bb = BitBoard(0b1001100); - bb.remove_piece_at(&sq); - assert!(!bb.has_piece_at(&sq)); + bb.remove_piece_at(sq); + assert!(!bb.has_piece_at(sq)); } #[test] - fn pieces() { - let bb = BitBoard(0x1001_1010); // e4 + fn single_rank_occupancy() { + let bb = BitBoard(0b01010100); + let expected_squares = [Square::G1, Square::E1, Square::C1]; + for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) { + assert_eq!(a, b); + } + } - 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); + #[test] + fn occupancy_spot_check() { + let bb = + BitBoard(0b10000000_00000000_00100000_00000100_00000000_00000000_00010000_00001000); + + let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1]; + + for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) { + assert_eq!(a, b); + } } }