BitBoard changes
- Clean up operator traits: remove the & versions and make the macro do more with less input - Implement From<Square> for BitBoards: simplify conversion of Squares to BitBoards - Take BitBoards by value in several places - Clean up unit tests
This commit is contained in:
parent
2105004dc2
commit
ff839db041
1 changed files with 48 additions and 47 deletions
|
@ -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<Square> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue