chessfriend/board/src/bitboard.rs

152 lines
3.2 KiB
Rust
Raw Normal View History

// Eryn Wells <eryn@erynwells.me>
use crate::square::Square;
use std::ops::{BitAnd, BitOr, Not};
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitBoard(u64);
impl BitBoard {
pub fn empty() -> BitBoard {
BitBoard(0)
}
pub fn from_bit_field(bits: u64) -> BitBoard {
BitBoard(bits)
}
fn is_empty(&self) -> bool {
self.0 == 0
}
fn has_piece_at(&self, sq: &Square) -> bool {
(self.0 & (1 << sq.index)) > 0
}
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)
}
#[cfg(target_arch = "arm")]
fn _arm_count_leading_zeros(&self) -> u8 {
let mut number_of_leading_zeros: u8 = 0;
unsafe {
asm!(
"clz {count}, {bitfield}",
count = out(reg) number_of_leading_zeros,
bitfield = in(reg) self.0,
);
}
number_of_leading_zeros
}
}
impl BitAnd for BitBoard {
type Output = BitBoard;
#[inline]
fn bitand(self, rhs: Self) -> Self {
BitBoard(self.0 & rhs.0)
}
}
impl BitAnd<&BitBoard> for BitBoard {
type Output = BitBoard;
#[inline]
fn bitand(self, rhs: &Self) -> Self {
BitBoard(self.0 & rhs.0)
}
}
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)
}
}
impl BitOr for BitBoard {
type Output = BitBoard;
#[inline]
fn bitor(self, rhs: Self) -> Self {
BitBoard(self.0 | rhs.0)
}
}
impl BitOr<&BitBoard> for BitBoard {
type Output = BitBoard;
#[inline]
fn bitor(self, rhs: &Self) -> Self {
BitBoard(self.0 | rhs.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::square::Square;
#[test]
fn is_empty() {
assert!(BitBoard(0).is_empty());
}
#[test]
fn has_piece_at() {
let bb = BitBoard(0b1001100);
assert!(bb.has_piece_at(
&Square::from_algebraic_string("a3").expect("Unable to get square for 'a3'")
));
assert!(!bb.has_piece_at(
&Square::from_algebraic_string("a2").expect("Unable to get square for 'a2'")
));
}
#[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));
}
#[cfg(target_arch = "arm")]
#[test]
fn arm_count_leading_zeros() {
assert_eq!(BitBoard(0)._arm_count_leading_zeros(), 0);
assert_eq!(BitBoard(0b10)._arm_count_leading_zeros(), 62);
assert_eq!(BitBoard(0b1010)._arm_count_leading_zeros(), 60);
assert_eq!(BitBoard(0x80000000)._arm_count_leading_zeros(), 0);
}
}