From 4a354004b4b7393bd7ae6d7990365664550b3793 Mon Sep 17 00:00:00 2001 From: Paul-Nicolas Madelaine Date: Fri, 24 Oct 2025 00:55:02 +0200 Subject: [PATCH] wip --- src/bitboard.rs | 38 +++++++++++--- src/lookup.rs | 131 ++++++++++++++++++++++++++---------------------- 2 files changed, 102 insertions(+), 67 deletions(-) diff --git a/src/bitboard.rs b/src/bitboard.rs index 3c920ca..fb10978 100644 --- a/src/bitboard.rs +++ b/src/bitboard.rs @@ -12,13 +12,13 @@ pub struct Bitboard(pub u64); impl Bitboard { /// Returns an empty bitboard. #[inline] - pub fn new() -> Self { + pub const fn new() -> Self { Self(0) } /// Returns `true` if the bitboard is empty. #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.0 == 0 } @@ -45,7 +45,7 @@ impl Bitboard { /// Removes the square with the smallest index and returns it, or `None` if the bitboard is empty. #[inline] - pub fn pop(&mut self) -> Option { + pub const fn pop(&mut self) -> Option { let Self(ref mut mask) = self; let square = match mask { 0 => None, @@ -75,7 +75,7 @@ impl Bitboard { /// Returns the vertical symmetry of the bitboard. #[inline] - pub fn mirror(self) -> Self { + pub const fn mirror(self) -> Self { let [a, b, c, d, e, f, g, h] = self.0.to_le_bytes(); Self(u64::from_le_bytes([h, g, f, e, d, c, b, a])) } @@ -129,25 +129,49 @@ impl std::fmt::Debug for Bitboard { } } +/// # Operators +impl Bitboard { + #[inline] + pub const fn eq(self, rhs: Self) -> bool { + self.0 == rhs.0 + } + #[inline] + pub const fn not(self) -> Self { + Self(!self.0) + } + #[inline] + pub const fn or(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } + #[inline] + pub const fn and(self, rhs: Self) -> Self { + Self(self.0 & rhs.0) + } + #[inline] + pub const fn xor(self, rhs: Self) -> Self { + Self(self.0 ^ rhs.0) + } +} + impl std::ops::BitOr for Bitboard { type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) + self.or(rhs) } } impl std::ops::BitAnd for Bitboard { type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self::Output { - Self(self.0 & rhs.0) + self.and(rhs) } } impl std::ops::BitXor for Bitboard { type Output = Self; #[inline] fn bitxor(self, rhs: Self) -> Self::Output { - Self(self.0 ^ rhs.0) + self.xor(rhs) } } impl std::ops::BitOrAssign for Bitboard { diff --git a/src/lookup.rs b/src/lookup.rs index aaabdf3..3a685ff 100644 --- a/src/lookup.rs +++ b/src/lookup.rs @@ -6,8 +6,11 @@ macro_rules! loop_subsets { ($premask: ident, $subset: ident, $e: expr) => {{ let mut $subset: u64 = 0; loop { - $subset = $subset.wrapping_sub($premask) & $premask; - $e + $subset = $subset.wrapping_sub($premask.0) & $premask.0; + { + let $subset = Bitboard($subset); + $e + } if $subset == 0 { break; } @@ -96,7 +99,7 @@ macro_rules! loop_all_directions { macro_rules! by_direction { ($d: ident, $e: expr) => {{ - let mut res = [Bitboard(0); 8]; + let mut res = [Bitboard::new(); 8]; let mut $d: u8 = 0; while $d < 8 { res[$d as usize] = { @@ -111,21 +114,21 @@ macro_rules! by_direction { const RAYS: BySquare> = by_square!( square, - ByDirection([Bitboard(0); 8]), + ByDirection([Bitboard::new(); 8]), by_direction!(direction, { let mut square = square; - let mut res = 0; + let mut res = Bitboard::new(); while let Some(x) = square.trans(direction) { square = x; - res |= square.bitboard().0; + res = res.or(square.bitboard()); } - Bitboard(res) + res }) ); -const LINES: BySquare> = by_square!(a, BySquare([Bitboard(0); 64]), { - by_square!(b, Bitboard(0), { - let mut res = Bitboard(0); +const LINES: BySquare> = by_square!(a, BySquare([Bitboard::new(); 64]), { + by_square!(b, Bitboard::new(), { + let mut res = Bitboard::new(); loop_all_directions!(d, { let r = *RAYS.get_const(a).get_const(d); if r.contains(b) { @@ -136,31 +139,31 @@ const LINES: BySquare> = by_square!(a, BySquare([Bitboard(0); }) }); -const SEGMENTS: BySquare> = by_square!(a, BySquare([Bitboard(0); 64]), { - by_square!(b, Bitboard(0), { - let mut res = 0; +const SEGMENTS: BySquare> = by_square!(a, BySquare([Bitboard::new(); 64]), { + by_square!(b, Bitboard::new(), { + let mut res = Bitboard::new(); loop_all_directions!(d, { let r = *RAYS.get_const(a).get_const(d); if r.contains(b) { - res = r.0 & !RAYS.get_const(b).get_const(d).0; + res = r.and(RAYS.get_const(b).get_const(d).not()); } }); - Bitboard(res | b.bitboard().0) + res.or(b.bitboard()) }) }); -const KING_MOVES: BySquare = by_square!(sq, Bitboard(0), { - let mut res = 0; +const KING_MOVES: BySquare = by_square!(sq, Bitboard::new(), { + let mut res = Bitboard::new(); loop_all_directions!(d, { if let Some(x) = sq.trans(d) { - res |= x.bitboard().0; + res = res.or(x.bitboard()); } }); - Bitboard(res) + res }); -const KNIGHT_MOVES: BySquare = by_square!(s, Bitboard(0), { - let mut res = Bitboard(0); +const KNIGHT_MOVES: BySquare = by_square!(s, Bitboard::new(), { + let mut res = Bitboard::new(); if let Some(s) = s.trans(Direction::North) { if let Some(s) = s.trans(Direction::NorthEast) { res.insert(s); @@ -202,8 +205,8 @@ const PAWN_ATTACKS: ByColor> = { Color::White => Direction::North, Color::Black => Direction::South, }; - by_square!(square, Bitboard(0), { - let mut res = Bitboard(0); + by_square!(square, Bitboard::new(), { + let mut res = Bitboard::new(); if let Some(square) = square.trans(direction) { if let Some(s) = square.trans(Direction::East) { res.insert(s) @@ -219,7 +222,7 @@ const PAWN_ATTACKS: ByColor> = { const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -> Bitboard { let ray = *RAYS.get_const(square).get_const(direction); - let blockers = Bitboard(blockers.0 & ray.0); + let blockers = blockers.or(ray); let square = if (direction as u8) < 4 { Bitboard::first(&blockers) } else { @@ -227,7 +230,7 @@ const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) - }; match square { None => ray, - Some(square) => Bitboard(ray.0 & !RAYS.get_const(square).get_const(direction).0), + Some(square) => ray.and(RAYS.get_const(square).get_const(direction).not()), } } @@ -257,25 +260,33 @@ pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard { } const fn bishop_premask(square: Square) -> Bitboard { - let mut premask = 0; + let mut premask = Bitboard::new(); loop_bishop_directions!(direction, { - premask |= RAYS.get_const(square).get_const(direction).0; + premask = premask.or(*RAYS.get_const(square).get_const(direction)); }); - premask &= !Rank::First.bitboard().0; - premask &= !Rank::Eighth.bitboard().0; - premask &= !File::A.bitboard().0; - premask &= !File::H.bitboard().0; - Bitboard(premask) + premask = premask + .and(Rank::First.bitboard().not()) + .and(Rank::Eighth.bitboard().not()) + .and(File::A.bitboard().not()) + .and(File::H.bitboard().not()); + premask } const fn rook_premask(square: Square) -> Bitboard { let rays = RAYS.get_const(square); - let mut premask = 0; - premask |= rays.get_const(Direction::East).0 & !File::H.bitboard().0; - premask |= rays.get_const(Direction::North).0 & !Rank::Eighth.bitboard().0; - premask |= rays.get_const(Direction::West).0 & !File::A.bitboard().0; - premask |= rays.get_const(Direction::South).0 & !Rank::First.bitboard().0; - Bitboard(premask) + Bitboard::new() + .or(rays + .get_const(Direction::East) + .and(File::H.bitboard().not())) + .or(rays + .get_const(Direction::North) + .and(Rank::Eighth.bitboard().not())) + .or(rays + .get_const(Direction::West) + .and(File::A.bitboard().not())) + .or(rays + .get_const(Direction::South) + .and(Rank::First.bitboard().not())) } const MAGICS: (BySquare, BySquare, usize) = { @@ -284,17 +295,17 @@ const MAGICS: (BySquare, BySquare, usize) = { by_square!( square, Magic { - premask: Bitboard(0), + premask: Bitboard::new(), factor: 0, offset: 0 }, { - let premask = bishop_premask(square).0; + let premask = bishop_premask(square); let factor = bishop_factor(square); let mut i = usize::MAX; let mut j = 0; loop_subsets!(premask, blockers, { - let cur = hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)); + let cur = hash(BISHOP_SHR, factor, blockers.or(premask.not())); if cur < i { i = cur; } @@ -305,7 +316,7 @@ const MAGICS: (BySquare, BySquare, usize) = { let offset = len as isize - i as isize; len += j - i + 1; Magic { - premask: Bitboard(!premask), + premask: premask.not(), factor, offset, } @@ -314,17 +325,17 @@ const MAGICS: (BySquare, BySquare, usize) = { by_square!( square, Magic { - premask: Bitboard(0), + premask: Bitboard::new(), factor: 0, offset: 0 }, { - let premask = rook_premask(square).0; + let premask = rook_premask(square); let factor = rook_factor(square); let mut i = usize::MAX; let mut j = 0; loop_subsets!(premask, blockers, { - let cur = hash(ROOK_SHR, factor, Bitboard(blockers | !premask)); + let cur = hash(ROOK_SHR, factor, blockers.or(premask.not())); if cur < i { i = cur; } @@ -335,7 +346,7 @@ const MAGICS: (BySquare, BySquare, usize) = { let offset = len as isize - i as isize; len += j - i + 1; Magic { - premask: Bitboard(!premask), + premask: premask.not(), factor, offset, } @@ -354,23 +365,23 @@ struct Magic { #[allow(long_running_const_eval)] const MAGIC_TABLE: [Bitboard; MAGICS.2] = { - let mut table = [Bitboard(0); MAGICS.2]; + let mut table = [Bitboard::new(); MAGICS.2]; by_square!(square, (), { let Magic { premask, factor, offset, } = *MAGICS.0.get_const(square); - let premask = !premask.0; + let premask = premask.not(); loop_subsets!(premask, blockers, { - let index = (hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize + offset) - as usize; - let mut res = 0; + let index = + (hash(BISHOP_SHR, factor, blockers.or(premask.not())) as isize + offset) as usize; + let mut res = Bitboard::new(); loop_bishop_directions!(direction, { - res |= blocked_ray(square, direction, Bitboard(blockers)).0; + res = res.or(blocked_ray(square, direction, blockers)); }); - assert!(table[index].0 == 0 || table[index].0 == res); - table[index] = Bitboard(res); + assert!(table[index].is_empty() || table[index].eq(res)); + table[index] = res; }); }); by_square!(square, (), { @@ -379,16 +390,16 @@ const MAGIC_TABLE: [Bitboard; MAGICS.2] = { factor, offset, } = *MAGICS.1.get_const(square); - let premask = !premask.0; + let premask = premask.not(); loop_subsets!(premask, blockers, { let index = - (offset + hash(ROOK_SHR, factor, Bitboard(blockers | !premask)) as isize) as usize; - let mut res = 0; + (offset + hash(ROOK_SHR, factor, blockers.or(premask.not())) as isize) as usize; + let mut res = Bitboard::new(); loop_rook_directions!(direction, { - res |= blocked_ray(square, direction, Bitboard(blockers)).0; + res = res.or(blocked_ray(square, direction, blockers)); }); - assert!(table[index].0 == 0 || table[index].0 == res); - table[index] = Bitboard(res); + assert!(table[index].is_empty() || table[index].eq(res)); + table[index] = res; }); }); table