/// 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"); } /// Return bitboard cardinality, aka number of elements in the set pub fn pop_count(bb: Bitboard) -> u8 { if bb == 0 { return 0; } return pop_count(bb >> 1) + (bb & 1) as u8; } /// Return Bitboard with only Least Single Bit pub fn ls1b(bb: Bitboard) -> u64 { if bb == 0 { return 0 } bb & !(bb - 1) } /// Log base 2 (aka Trailing Zero Count) /// /// WARNING: Only works for SINGLE Bitboards /// Useful for calculating bit-index of LS1B pub fn bitscan(bb: Bitboard) -> u8 { debug_assert!(pop_count(bb) == 1, "Bitscan only works for SINGLE Bitboards!"); pop_count(bb - 1) } pub fn bitscan_and_reset(bb: &mut Bitboard) -> u8 { let ls1b_bitboard = ls1b(*bb); *bb ^= ls1b_bitboard; bitscan(ls1b_bitboard) } pub fn serialize_bitboard(bb: Bitboard) -> Vec { let mut serialized = Vec::with_capacity(64); let mut bitboard = bb; while bitboard > 0 { serialized.push(bitscan_and_reset(&mut bitboard)); } serialized } #[cfg(test)] mod tests { use super::*; #[test] fn test_pop_count() { assert_eq!(pop_count(127), 7); } #[test] fn test_ls1b() { assert_eq!(ls1b(38), 2); assert_eq!(ls1b(16), 16); assert_eq!(ls1b(20), 4); } #[test] fn test_bitscan() { assert_eq!(bitscan(4), 2); assert_eq!(bitscan(16), 4); assert_eq!(bitscan(64), 6); assert_eq!(bitscan(128), 7); } #[test] #[should_panic(expected = "Bitscan only works for SINGLE Bitboards!")] fn test_bitscan_with_non_single_bb() { bitscan(5); } #[test] fn test_bitscan_and_reset() { assert_eq!(bitscan(4), 2); assert_eq!(bitscan(16), 4); assert_eq!(bitscan(64), 6); assert_eq!(bitscan(128), 7); } #[test] fn test_serialize_bitboard() { let bb = 1 << 4 | 1 << 15 | 1 << 60; let serialized = serialize_bitboard(bb); assert_eq!(serialized[0], 4); assert_eq!(serialized[1], 15); assert_eq!(serialized[2], 60); } }