diff options
Diffstat (limited to 'src/bitboard.rs')
-rw-r--r-- | src/bitboard.rs | 163 |
1 files changed, 89 insertions, 74 deletions
diff --git a/src/bitboard.rs b/src/bitboard.rs index ed7ec1b..ad21664 100644 --- a/src/bitboard.rs +++ b/src/bitboard.rs @@ -3,40 +3,32 @@ use crate::square::Square; /// Finite set of up to 64 bits representing chess board squares pub type Bitboard = u64; -/// Print bitboard on screen in the same way squares appear in memory -/// (i.e the board is actually flipped along X) -#[allow(dead_code)] -pub fn print(bb: Bitboard, title: &str) { - println!("\n {}", title); - for rank in (0..8).rev() { - print!("{}|", rank + 1); - for file in 0..8 { - let index = rank * 8 + file; - print!("{}", if bb >> index & 1 == 1 { "⚫" } else { ". " }); - if file == 7 { - println!(); - } - } - } - return println!(" a b c d e f g h"); -} +pub trait BitboardFns { + /// Print bitboard on the screen + fn print(self, title: &str) -> (); -/// Return bitboard cardinality, aka number of elements in the set -pub fn pop_count(mut bb: Bitboard) -> u8 { - let mut count = 0; - while bb > 0 { - count += 1; - bb &= bb - 1; - } - return count; -} + /// Return bitboard cardinality, aka number of elements in the set + fn pop_count(self) -> u8; -/// Return Bitboard with only Least Single Bit -pub fn ls1b(bb: Bitboard) -> Bitboard { - if bb == 0 { - return 0 - } - bb & !(bb - 1) + /// Return Bitboard with only Least Single Bit + fn ls1b(self) -> Self; + + /// Return the square corresponding to Least Single Bit + /// using De Brujin method. For single Bitboards it works + /// like a mapper from Bitboards to Squares. + /// + /// ```rust + /// # use chessnost::{bitboard::BitboardFns, square::Square}; + /// assert_eq!(5.bitscan(), Square::from(0)); + /// assert_eq!(4.bitscan(), Square::C1); + /// ``` + fn bitscan(self) -> Square; + + /// Perform bitscan and reset the *ls1b* + fn bitscan_and_reset(&mut self) -> Square; + + /// Convert bitboard into the list of squares + fn serialize(self) -> Vec<Square>; } const DE_BRUJIN_SEQUENCE: [u8; 64] = [ @@ -50,38 +42,62 @@ const DE_BRUJIN_SEQUENCE: [u8; 64] = [ 25, 14, 19, 9, 13, 8, 7, 6 ]; -/// Return the square corresponding to Least Single Bit -/// using De Brujin method. For single Bitboards it works -/// like a mapper from Bitboards to Squares. -/// -/// ```rust -/// # use chessnost::{bitboard::bitscan, square::Square}; -/// assert_eq!(bitscan(5), Square::from(0)); -/// assert_eq!(bitscan(4), Square::C1); -/// ``` -pub fn bitscan(bb: Bitboard) -> Square { - // TODO: generate private De Brujin routine - debug_assert!(bb != 0, "Can not bitscan empty bitboard"); - let magic: u64 = 0x03f79d71b4cb0a89; - let ls1b = ls1b(bb); - let index = DE_BRUJIN_SEQUENCE[(((ls1b as u128 * magic as u128) as u64) >> 58) as usize]; - Square::from(index) -} +impl BitboardFns for Bitboard { + fn print(self, title: &str) -> () { + println!("\n {}", title); + for rank in (0..8).rev() { + print!("{}|", rank + 1); + for file in 0..8 { + let index = rank * 8 + file; + print!("{}", if self >> index & 1 == 1 { "⚫" } else { ". " }); + if file == 7 { + println!(); + } + } + } + return println!(" a b c d e f g h"); + } -/// Perform bitscan and reset the *ls1b* -pub fn bitscan_and_reset(bb: &mut Bitboard) -> Square { - let square = bitscan(*bb); - *bb &= *bb - 1; // Reset ls1b - square -} + fn pop_count(mut self) -> u8 { + let mut count = 0; + while self > 0 { + count += 1; + self &= self - 1; + } + return count; + } + + + fn ls1b(self) -> Self { + if self == 0 { + return 0 + } + self & !(self - 1) + } -/// Convert bitboard into the list of squares -pub fn serialize_bitboard(mut bb: Bitboard) -> Vec<Square> { - let mut serialized = Vec::with_capacity(64); - while bb > 0 { - serialized.push(bitscan_and_reset(&mut bb)); + + fn bitscan(self) -> Square { + // TODO: generate private De Brujin routine + debug_assert!(self != 0, "Can not bitscan empty bitboard"); + let magic: u64 = 0x03f79d71b4cb0a89; + let ls1b = self.ls1b(); + let index = DE_BRUJIN_SEQUENCE[(((ls1b as u128 * magic as u128) as u64) >> 58) as usize]; + Square::from(index) + } + + fn bitscan_and_reset(&mut self) -> Square { + let square = self.bitscan(); + *self &= *self - 1; // Reset ls1b + square + } + + fn serialize(mut self) -> Vec<Square> { + let mut serialized = Vec::with_capacity(64); + while self > 0 { + serialized.push(self.bitscan_and_reset()); + } + serialized } - serialized } #[cfg(test)] @@ -90,38 +106,37 @@ mod tests { #[test] fn test_pop_count() { - assert_eq!(pop_count(127), 7); + assert_eq!(127.pop_count(), 7); } #[test] fn test_ls1b() { - assert_eq!(ls1b(38), 2); - assert_eq!(ls1b(16), 16); - assert_eq!(ls1b(20), 4); + assert_eq!(38.ls1b(), 2); + assert_eq!(16.ls1b(), 16); + assert_eq!(20.ls1b(), 4); } #[test] fn test_bitscan() { - assert_eq!(bitscan(4), Square::from(2)); - assert_eq!(bitscan(16), Square::from(4)); - assert_eq!(bitscan(64), Square::from(6)); - assert_eq!(bitscan(128), Square::from(7)); + assert_eq!(4.bitscan(), Square::from(2)); + assert_eq!(16.bitscan(), Square::from(4)); + assert_eq!(64.bitscan(), Square::from(6)); + assert_eq!(128.bitscan(), Square::from(7)); } #[test] fn test_bitscan_with_non_single_bb() { - assert_eq!(bitscan(5), Square::from(0)); - assert_eq!(bitscan(6), Square::from(1)); - assert_eq!(bitscan(7), Square::from(0)); + assert_eq!(5.bitscan(), Square::from(0)); + assert_eq!(6.bitscan(), Square::from(1)); + assert_eq!(7.bitscan(), Square::from(0)); } #[test] fn test_serialize_bitboard() { let bb = 1 << 4 | 1 << 15 | 1 << 60; - let serialized = serialize_bitboard(bb); + let serialized = bb.serialize(); assert_eq!(serialized[0], Square::from(4)); assert_eq!(serialized[1], Square::from(15)); assert_eq!(serialized[2], Square::from(60)); } } - |