From 028549542ba9aa815589f968f60bccb9b58f21d0 Mon Sep 17 00:00:00 2001 From: Paul-Nicolas Madelaine Date: Wed, 22 Oct 2025 01:23:42 +0200 Subject: [PATCH] const lookup --- src/bitboard.rs | 2 +- src/board.rs | 3 + src/lib.rs | 8 - src/lookup.rs | 642 ++++++++++++++++++++++-------------------------- src/magics.rs | 16 +- src/main.rs | 3 - src/position.rs | 95 +++---- src/setup.rs | 14 +- 8 files changed, 361 insertions(+), 422 deletions(-) delete mode 100644 src/main.rs diff --git a/src/bitboard.rs b/src/bitboard.rs index a34a9ec..1adfd65 100644 --- a/src/bitboard.rs +++ b/src/bitboard.rs @@ -65,7 +65,7 @@ impl Bitboard { #[inline] pub const fn remove(&mut self, square: Square) { - todo!() + self.0 &= !(1 << square as u8); } /// Returns `true` if the bitboard contains the given square. diff --git a/src/board.rs b/src/board.rs index dca9dbf..d792ba4 100644 --- a/src/board.rs +++ b/src/board.rs @@ -24,6 +24,9 @@ macro_rules! container { pub fn get_mut(&mut self, k: $a) -> &mut T { unsafe { self.0.get_unchecked_mut(k as usize) } } + pub(crate) const fn get_const(&self, k: $a) -> &T { + &self.0[k as usize] + } } }; } diff --git a/src/lib.rs b/src/lib.rs index fc8e1d9..4f55879 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,11 +87,3 @@ pub mod uci; pub mod prelude { pub use crate::{position::Position, san::San, setup::Setup, uci::UciMove}; } - -pub fn test() { - use crate::bitboard::*; - use crate::board::*; - let d = &crate::lookup::LOOKUP; - let Bitboard(x) = d.pawn_attack(Color::White, Square::F7); - println!("{x:016x}"); -} diff --git a/src/lookup.rs b/src/lookup.rs index a5c9f72..dcd6fef 100644 --- a/src/lookup.rs +++ b/src/lookup.rs @@ -2,9 +2,6 @@ use crate::bitboard::*; use crate::board::*; use crate::magics::*; -#[allow(long_running_const_eval)] -pub(crate) static LOOKUP: Lookup = Lookup::compute(); - macro_rules! loop_bishop_directions { ($d: ident, $body: expr) => {{ { @@ -99,241 +96,160 @@ macro_rules! by_direction { }}; } -pub(crate) struct Rays(BySquare>); +const RAYS: BySquare> = by_square!( + square, + ByDirection([Bitboard(0); 8]), + by_direction!(direction, { + let mut square = square; + let mut res = 0; + while let Some(x) = square.trans(direction) { + square = x; + res |= square.bitboard().0; + } + Bitboard(res) + }) +); +const LINES: BySquare> = by_square!(a, BySquare([Bitboard(0); 64]), { + by_square!(b, Bitboard(0), { + let mut res = Bitboard(0); + loop_all_directions!(d, { + let r = *RAYS.get_const(a).get_const(d); + if r.contains(b) { + res = r; + } + }); + res + }) +}); -impl Rays { - pub(crate) const fn new() -> Self { - Self(by_square!( - square, - ByDirection([Bitboard(0); 8]), - by_direction!(direction, { - let mut square = square; - let mut res = 0; - while let Some(x) = square.trans(direction) { - square = x; - res |= square.bitboard().0; - } - Bitboard(res) - }) - )) - } - - #[inline] - pub(crate) const fn ray(&self, square: Square, direction: Direction) -> Bitboard { - (self.0).0[square as u8 as usize].0[direction as u8 as usize] - } - - pub(crate) const fn blocked( - &self, - square: Square, - direction: Direction, - blockers: Bitboard, - ) -> Bitboard { - let ray = self.ray(square, direction); - let blockers = Bitboard(blockers.0 & ray.0); - let square = if (direction as u8) < 4 { - Bitboard::first(&blockers) - } else { - Bitboard::last(&blockers) +const SEGMENTS: BySquare> = by_square!(a, BySquare([Bitboard(0); 64]), { + by_square!(b, Bitboard(0), { + let mut res = 0; + 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; + } + }); + Bitboard(res | b.bitboard().0) + }) +}); +const KING_MOVES: BySquare = by_square!(sq, Bitboard(0), { + let mut res = 0; + loop_all_directions!(d, { + if let Some(x) = sq.trans(d) { + res |= x.bitboard().0; + } + }); + Bitboard(res) +}); +const KNIGHT_MOVES: BySquare = by_square!(s, Bitboard(0), { + let mut res = Bitboard::new(); + if let Some(s) = s.trans(Direction::North) { + if let Some(s) = s.trans(Direction::NorthEast) { + res.insert(s); + } + if let Some(s) = s.trans(Direction::NorthWest) { + res.insert(s) }; - match square { - None => ray, - Some(square) => Bitboard(ray.0 & !self.ray(square, direction).0), - } } -} - -pub(crate) struct Lookup { - rays: Rays, - lines: BySquare>, - segments: BySquare>, - pawn_attacks: ByColor>, - king_moves: BySquare, - knight_moves: BySquare, - pub(crate) magics: Magics, -} - -impl Lookup { - #[inline] - pub(crate) fn line(&self, a: Square, b: Square) -> Bitboard { - *self.lines.get(a).get(b) + if let Some(s) = s.trans(Direction::West) { + if let Some(s) = s.trans(Direction::NorthWest) { + res.insert(s) + }; + if let Some(s) = s.trans(Direction::SouthWest) { + res.insert(s) + }; } - - #[inline] - pub(crate) fn segment(&self, a: Square, b: Square) -> Bitboard { - *self.segments.get(a).get(b) + if let Some(s) = s.trans(Direction::South) { + if let Some(s) = s.trans(Direction::SouthWest) { + res.insert(s) + }; + if let Some(s) = s.trans(Direction::SouthEast) { + res.insert(s) + }; } - - #[inline] - pub(crate) fn ray(&self, square: Square, direction: Direction) -> Bitboard { - self.rays.ray(square, direction) + if let Some(s) = s.trans(Direction::East) { + if let Some(s) = s.trans(Direction::SouthEast) { + res.insert(s) + }; + if let Some(s) = s.trans(Direction::NorthEast) { + res.insert(s) + }; } - - #[inline] - pub(crate) fn king(&self, square: Square) -> Bitboard { - *self.king_moves.get(square) - } - - #[inline] - pub(crate) fn knight(&self, square: Square) -> Bitboard { - *self.knight_moves.get(square) - } - - #[inline] - pub(crate) fn pawn_attack(&self, color: Color, square: Square) -> Bitboard { - *self.pawn_attacks.get(color).get(square) - } - - #[inline] - pub(crate) fn bishop(&self, square: Square, blockers: Bitboard) -> Bitboard { - self.magics.bishop(square, blockers) - } - - #[inline] - pub(crate) fn rook(&self, square: Square, blockers: Bitboard) -> Bitboard { - self.magics.rook(square, blockers) - } - - /// `role != Pawn` - #[inline] - pub(crate) fn targets(&self, role: Role, from: Square, blockers: Bitboard) -> Bitboard { - match role { - Role::Pawn => unreachable!(), - Role::Knight => self.knight(from), - Role::Bishop => self.bishop(from, blockers), - Role::Rook => self.rook(from, blockers), - Role::Queen => self.bishop(from, blockers) | self.rook(from, blockers), - Role::King => self.king(from), - } - } - - const fn compute() -> Self { - let rays = Rays::new(); - - let lines = by_square!(a, BySquare([Bitboard(0); 64]), { - by_square!(b, Bitboard(0), { - let mut res = Bitboard(0); - loop_all_directions!(d, { - let r = rays.ray(a, d); - if r.contains(b) { - res = r; - } - }); - res - }) - }); - - let segments: BySquare> = by_square!(a, BySquare([Bitboard(0); 64]), { - by_square!(b, Bitboard(0), { - let mut res = 0; - loop_all_directions!(d, { - let r = rays.ray(a, d); - if r.contains(b) { - res = r.0 & !rays.ray(b, d).0; - } - }); - Bitboard(res | b.bitboard().0) - }) - }); - - let pawn_attacks = by_color!(color, { - let direction = match color { - Color::White => Direction::North, - Color::Black => Direction::South, - }; - by_square!(square, Bitboard(0), { - let mut res = Bitboard(0); - if let Some(square) = square.trans(direction) { - if let Some(s) = square.trans(Direction::East) { - res.insert(s) - }; - if let Some(s) = square.trans(Direction::West) { - res.insert(s) - }; - } - res - }) - }); - - let king_moves = by_square!(sq, Bitboard(0), { - let mut res = 0; - loop_all_directions!(d, { - if let Some(x) = sq.trans(d) { - res |= x.bitboard().0; - } - }); - Bitboard(res) - }); - - let knight_moves = by_square!(s, Bitboard(0), { - let mut res = Bitboard::new(); - if let Some(s) = s.trans(Direction::North) { - if let Some(s) = s.trans(Direction::NorthEast) { - res.insert(s); - } - if let Some(s) = s.trans(Direction::NorthWest) { + res +}); +const PAWN_ATTACKS: ByColor> = { + by_color!(color, { + let direction = match color { + Color::White => Direction::North, + Color::Black => Direction::South, + }; + by_square!(square, Bitboard(0), { + let mut res = Bitboard(0); + if let Some(square) = square.trans(direction) { + if let Some(s) = square.trans(Direction::East) { res.insert(s) }; - } - if let Some(s) = s.trans(Direction::West) { - if let Some(s) = s.trans(Direction::NorthWest) { - res.insert(s) - }; - if let Some(s) = s.trans(Direction::SouthWest) { - res.insert(s) - }; - } - if let Some(s) = s.trans(Direction::South) { - if let Some(s) = s.trans(Direction::SouthWest) { - res.insert(s) - }; - if let Some(s) = s.trans(Direction::SouthEast) { - res.insert(s) - }; - } - if let Some(s) = s.trans(Direction::East) { - if let Some(s) = s.trans(Direction::SouthEast) { - res.insert(s) - }; - if let Some(s) = s.trans(Direction::NorthEast) { + if let Some(s) = square.trans(Direction::West) { res.insert(s) }; } res - }); + }) + }) +}; - let magics = Magics::compute(&rays); - - Self { - rays, - lines, - segments, - pawn_attacks, - king_moves, - knight_moves, - magics, - } +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 square = if (direction as u8) < 4 { + Bitboard::first(&blockers) + } else { + Bitboard::last(&blockers) + }; + match square { + None => ray, + Some(square) => Bitboard(ray.0 & !RAYS.get_const(square).get_const(direction).0), } } -// -------- Magics -------- - -const BISHOP_SHR: u8 = 55; -const ROOK_SHR: u8 = 52; - -const TABLE_SIZE: usize = 267_293; - -pub(crate) struct Magics { - bishop: BySquare, - rook: BySquare, - table: [Bitboard; TABLE_SIZE], +#[inline] +pub(crate) fn ray(square: Square, direction: Direction) -> Bitboard { + *RAYS.get(square).get(direction) +} +#[inline] +pub(crate) fn line(a: Square, b: Square) -> Bitboard { + *LINES.get(a).get(b) +} +#[inline] +pub(crate) fn segment(a: Square, b: Square) -> Bitboard { + *SEGMENTS.get(a).get(b) +} +#[inline] +pub(crate) fn king(square: Square) -> Bitboard { + *KING_MOVES.get(square) +} +#[inline] +pub(crate) fn knight(square: Square) -> Bitboard { + *KNIGHT_MOVES.get(square) +} +#[inline] +pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard { + *PAWN_ATTACKS.get(color).get(square) } -#[derive(Clone, Copy)] -struct Magic { - premask: Bitboard, - factor: u64, - offset: isize, +/// `role != Pawn` +#[inline] +pub(crate) fn targets(role: Role, from: Square, blockers: Bitboard) -> Bitboard { + match role { + Role::Pawn => unreachable!(), + Role::Knight => knight(from), + Role::Bishop => bishop(from, blockers), + Role::Rook => rook(from, blockers), + Role::Queen => bishop(from, blockers) | rook(from, blockers), + Role::King => king(from), + } } macro_rules! loop_subsets { @@ -349,142 +265,176 @@ macro_rules! loop_subsets { }}; } -impl Magics { - pub(crate) const fn compute(rays: &Rays) -> Self { - let null = Magic { - premask: Bitboard(0), - factor: 0, - offset: 0, - }; +const fn bishop_premask(square: Square) -> Bitboard { + let mut premask = 0; + loop_bishop_directions!(direction, { + premask |= RAYS.get_const(square).get_const(direction).0; + }); + premask &= !Rank::First.bitboard().0; + premask &= !Rank::Eighth.bitboard().0; + premask &= !File::A.bitboard().0; + premask &= !File::H.bitboard().0; + Bitboard(premask) +} - let mut table = [Bitboard(0); TABLE_SIZE]; - let mut len: usize = 0; - - let bishop = by_square!(square, null, { - let mut premask = 0; - loop_bishop_directions!(direction, { - premask |= rays.ray(square, direction).0; - }); - premask &= !Rank::First.bitboard().0; - premask &= !Rank::Eighth.bitboard().0; - premask &= !File::A.bitboard().0; - premask &= !File::H.bitboard().0; - - let factor = bishop_factors(square); - - let mut a = usize::MAX; - loop_subsets!(premask, blockers, { - let cur = hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)); - if cur < a { - a = cur; - } - }); - let offset = len as isize - a as isize; - - loop_subsets!(premask, blockers, { - let index = (offset - + hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize) - as usize; - let mut res = 0; - loop_bishop_directions!(direction, { - res |= rays.blocked(square, direction, Bitboard(blockers)).0; - }); - if table[index].0 != 0 && table[index].0 != res { - panic!() - } - if index >= len { - len = index + 1; - } - table[index] = Bitboard(res); - }); +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) +} +const MAGICS: (BySquare, BySquare, usize) = { + let mut len: usize = 0; + ( + by_square!( + square, Magic { - premask: Bitboard(!premask), - factor, - offset, - } - }); - - let rook = by_square!(square, null, { - let mut premask = 0; - premask |= rays.ray(square, Direction::East).0 & !File::H.bitboard().0; - premask |= rays.ray(square, Direction::North).0 & !Rank::Eighth.bitboard().0; - premask |= rays.ray(square, Direction::West).0 & !File::A.bitboard().0; - premask |= rays.ray(square, Direction::South).0 & !Rank::First.bitboard().0; - - let factor = rook_factors(square); - - let mut a = usize::MAX; - loop_subsets!(premask, blockers, { - let cur = hash(ROOK_SHR, factor, Bitboard(blockers | !premask)); - if cur < a { - a = cur; - } - }); - let offset = len as isize - a as isize; - - loop_subsets!(premask, blockers, { - let index = (offset - + hash(ROOK_SHR, factor, Bitboard(blockers | !premask)) as isize) - as usize; - let mut res = 0; - loop_rook_directions!(direction, { - res |= rays.blocked(square, direction, Bitboard(blockers)).0; + premask: Bitboard(0), + factor: 0, + offset: 0 + }, + { + let premask = bishop_premask(square).0; + let factor = bishop_factor(square); + let mut a = usize::MAX; + let mut b = 0; + loop_subsets!(premask, blockers, { + let cur = hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)); + if cur < a { + a = cur; + } + if cur > b { + b = cur; + } }); - if table[index].0 != 0 && table[index].0 != res { - panic!() + assert!(b > a); + let offset = len as isize - a as isize; + len += b - a + 1; + Magic { + premask: Bitboard(!premask), + factor, + offset, } - if index >= len { - len = index + 1; - } - table[index] = Bitboard(res); - }); - - Magic { - premask: Bitboard(!premask), - factor, - offset, } - }); + ), + by_square!( + square, + Magic { + premask: Bitboard(0), + factor: 0, + offset: 0 + }, + { + let premask = rook_premask(square).0; + let factor = rook_factor(square); + let mut a = usize::MAX; + let mut b = 0; + loop_subsets!(premask, blockers, { + let cur = hash(ROOK_SHR, factor, Bitboard(blockers | !premask)); + if cur < a { + a = cur; + } + if cur > b { + b = cur; + } + }); + assert!(b > a); + let offset = len as isize - a as isize; + len += b - a + 1; + Magic { + premask: Bitboard(!premask), + factor, + offset, + } + } + ), + len, + ) +}; - // if len != TABLE_SIZE { - // panic!() - // } +#[derive(Clone, Copy)] +struct Magic { + premask: Bitboard, + factor: u64, + offset: isize, +} - Self { - bishop, - rook, - table, - } - } - - #[inline] - pub(crate) fn bishop(&self, square: Square, blockers: Bitboard) -> Bitboard { - unsafe { self.get_unchecked(BISHOP_SHR, *self.bishop.get(square), blockers) } - } - - #[inline] - pub(crate) fn rook(&self, square: Square, blockers: Bitboard) -> Bitboard { - unsafe { self.get_unchecked(ROOK_SHR, *self.rook.get(square), blockers) } - } - - #[inline] - unsafe fn get_unchecked(&self, shr: u8, magic: Magic, blockers: Bitboard) -> Bitboard { +#[allow(long_running_const_eval)] +const MAGIC_TABLE: [Bitboard; MAGICS.2] = { + let mut table = [Bitboard(0); MAGICS.2]; + by_square!(square, (), { let Magic { premask, factor, offset, - } = magic; - debug_assert!(self - .table - .get( - (hash(shr, factor, blockers | premask) as isize) - .checked_add(offset) - .unwrap() as usize - ) - .is_some()); - *self.table.get_unchecked( - ((hash(shr, factor, blockers | premask) as isize).unchecked_add(offset)) as usize, - ) - } + } = *MAGICS.0.get_const(square); + let premask = !premask.0; + loop_subsets!(premask, blockers, { + let index = (hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize + offset) + as usize; + let mut res = 0; + loop_bishop_directions!(direction, { + res |= blocked_ray(square, direction, Bitboard(blockers)).0; + }); + assert!(table[index].0 == 0 || table[index].0 == res); + table[index] = Bitboard(res); + }); + }); + by_square!(square, (), { + let Magic { + premask, + factor, + offset, + } = *MAGICS.1.get_const(square); + let premask = !premask.0; + loop_subsets!(premask, blockers, { + let index = + (offset + hash(ROOK_SHR, factor, Bitboard(blockers | !premask)) as isize) as usize; + let mut res = 0; + loop_rook_directions!(direction, { + res |= blocked_ray(square, direction, Bitboard(blockers)).0; + }); + assert!(table[index].0 == 0 || table[index].0 == res); + table[index] = Bitboard(res); + }); + }); + table +}; + +#[inline] +pub(crate) fn bishop(square: Square, blockers: Bitboard) -> Bitboard { + unsafe { magic_aux(BISHOP_SHR, *(MAGICS.0).get(square), blockers) } +} + +#[inline] +pub(crate) fn rook(square: Square, blockers: Bitboard) -> Bitboard { + unsafe { magic_aux(ROOK_SHR, *(MAGICS.1).get(square), blockers) } +} + +#[inline] +unsafe fn magic_aux(shr: u8, magic: Magic, blockers: Bitboard) -> Bitboard { + let Magic { + premask, + factor, + offset, + } = magic; + debug_assert!(MAGIC_TABLE + .get( + (hash(shr, factor, blockers | premask) as isize) + .checked_add(offset) + .unwrap() as usize + ) + .is_some()); + *MAGIC_TABLE.get_unchecked( + ((hash(shr, factor, blockers | premask) as isize).unchecked_add(offset)) as usize, + ) +} + +#[inline] +const fn hash(shr: u8, factor: u64, x: Bitboard) -> usize { + (x.0.wrapping_mul(factor) >> shr) as usize } diff --git a/src/magics.rs b/src/magics.rs index e37a0f6..d338b91 100644 --- a/src/magics.rs +++ b/src/magics.rs @@ -1,16 +1,7 @@ -use crate::bitboard::*; -use crate::board::*; +use crate::board::Square; pub(crate) const BISHOP_SHR: u8 = 55; -pub(crate) const ROOK_SHR: u8 = 52; - -pub(crate) const TABLE_SIZE: usize = 0; - -pub(crate) const fn hash(shr: u8, factor: u64, x: Bitboard) -> usize { - (x.0.wrapping_mul(factor) >> shr) as usize -} - -pub(crate) const fn bishop_factors(square: Square) -> u64 { +pub(crate) const fn bishop_factor(square: Square) -> u64 { match square { Square::A1 => 0x0000404040404040, Square::B1 => 0x0040C100081000E8, @@ -79,7 +70,8 @@ pub(crate) const fn bishop_factors(square: Square) -> u64 { } } -pub(crate) const fn rook_factors(square: Square) -> u64 { +pub(crate) const ROOK_SHR: u8 = 52; +pub(crate) const fn rook_factor(square: Square) -> u64 { match square { Square::A1 => 0x002000A28110000C, Square::B1 => 0x0018000C01060001, diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index f6e92c7..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - eschac::test(); -} diff --git a/src/position.rs b/src/position.rs index 934a349..ec14742 100644 --- a/src/position.rs +++ b/src/position.rs @@ -3,6 +3,7 @@ use crate::array_vec::*; use crate::bitboard::*; use crate::board::*; +use crate::lookup; use crate::san::*; use crate::setup::*; use crate::uci::*; @@ -229,7 +230,6 @@ impl Position { /// When possible, this inverts the color to play and removes the en passant square if it /// exists. pub fn pass(&self) -> Option { - let d = &crate::lookup::LOOKUP; let setup = &self.0; let blockers = setup.p_b_q | setup.n_b_k | setup.r_q_k; let k = setup.n_b_k & setup.r_q_k; @@ -244,10 +244,10 @@ impl Position { }; let king_square = (us & k).next().unwrap(); let checkers = them - & (d.pawn_attack(setup.turn, king_square) & p - | d.knight(king_square) & n - | d.bishop(king_square, blockers) & (q | b) - | d.rook(king_square, blockers) & (q | r)); + & (lookup::pawn_attack(setup.turn, king_square) & p + | lookup::knight(king_square) & n + | lookup::bishop(king_square, blockers) & (q | b) + | lookup::rook(king_square, blockers) & (q | r)); checkers.is_empty().then(|| { Self(Setup { turn: !setup.turn, @@ -938,7 +938,6 @@ impl Position { en_passant, castling_rights, } = self.0; - let d = &crate::lookup::LOOKUP; let blockers = p_b_q | n_b_k | r_q_k; let (us, them) = match turn { @@ -968,10 +967,10 @@ impl Position { let forward = turn.forward(); - let x = d.bishop(king_square, blockers); - let y = d.rook(king_square, blockers); - let checkers = d.pawn_attack(turn, king_square) & theirs.pawn() - | d.knight(king_square) & theirs.knight() + let x = lookup::bishop(king_square, blockers); + let y = lookup::rook(king_square, blockers); + let checkers = lookup::pawn_attack(turn, king_square) & theirs.pawn() + | lookup::knight(king_square) & theirs.knight() | x & theirs.bishop() | y & theirs.rook(); @@ -980,10 +979,10 @@ impl Position { let blockers = blockers ^ ours.king(); theirs .king() - .map(|sq| d.king(sq)) - .chain(theirs.bishop().map(|sq| d.bishop(sq, blockers))) - .chain(theirs.rook().map(|sq| d.rook(sq, blockers))) - .chain(theirs.knight().map(|sq| d.knight(sq))) + .map(|sq| lookup::king(sq)) + .chain(theirs.bishop().map(|sq| lookup::bishop(sq, blockers))) + .chain(theirs.rook().map(|sq| lookup::rook(sq, blockers))) + .chain(theirs.knight().map(|sq| lookup::knight(sq))) .chain(std::iter::once( theirs.pawn().trans(!forward).trans(Direction::East), )) @@ -994,7 +993,7 @@ impl Position { }; // king moves visitor.moves( - (global_mask_to & d.king(king_square) & !us & !attacked).map(|to| RawMove { + (global_mask_to & lookup::king(king_square) & !us & !attacked).map(|to| RawMove { kind: MoveType::KingMove, from: king_square, to, @@ -1052,17 +1051,17 @@ impl Position { } let blockers_x_ray = blockers & !(x | y); - let pinned_diagonally = (d.bishop(king_square, blockers_x_ray) & theirs.bishop()) - .map(|sq| d.segment(king_square, sq)) + let pinned_diagonally = (lookup::bishop(king_square, blockers_x_ray) & theirs.bishop()) + .map(|sq| lookup::segment(king_square, sq)) .reduce_or(); - let pinned_horizontally = (d.rook(king_square, blockers_x_ray) & theirs.rook()) - .map(|sq| d.segment(king_square, sq)) + let pinned_horizontally = (lookup::rook(king_square, blockers_x_ray) & theirs.rook()) + .map(|sq| lookup::segment(king_square, sq)) .reduce_or(); let pinned = pinned_diagonally | pinned_horizontally; let checker = checkers.first(); let block_check = checker - .map(|checker| d.segment(king_square, checker)) + .map(|checker| lookup::segment(king_square, checker)) .unwrap_or(Bitboard(!0)); let target_mask = global_mask_to & block_check; @@ -1105,7 +1104,7 @@ impl Position { // pawn attacks kingside { let targets = - (global_mask_from & ours.pawn() & (!pinned | d.ray(king_square, kside))) + (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, kside))) .trans(kside) & them & target_mask; @@ -1127,7 +1126,7 @@ impl Position { // pawn attacks queenside { let targets = - (global_mask_from & ours.pawn() & (!pinned | d.ray(king_square, qside))) + (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, qside))) .trans(qside) & them & target_mask; @@ -1167,23 +1166,27 @@ impl Position { if block_check.contains(to) || checker.is_none_or(|checker| checker == capture_square) { - let candidates = d.pawn_attack(!turn, to) & ours.pawn(); + let candidates = lookup::pawn_attack(!turn, to) & ours.pawn(); let blockers = blockers ^ capture_square.bitboard(); let pinned = pinned - | (d.rook(king_square, blockers & !(d.rook(king_square, blockers))) - & theirs.rook()) - .map(|sq| d.segment(king_square, sq)) + | (lookup::rook( + king_square, + blockers & !(lookup::rook(king_square, blockers)), + ) & theirs.rook()) + .map(|sq| lookup::segment(king_square, sq)) .reduce_or(); - (global_mask_from & candidates & (!pinned | d.segment(king_square, to))) - .for_each(|from| { - visitor.en_passant_is_legal(); - visitor.moves(std::iter::once(RawMove { - kind: MoveType::EnPassant, - from, - to, - role: Role::Pawn, - })) - }) + (global_mask_from + & candidates + & (!pinned | lookup::segment(king_square, to))) + .for_each(|from| { + visitor.en_passant_is_legal(); + visitor.moves(std::iter::once(RawMove { + kind: MoveType::EnPassant, + from, + to, + role: Role::Pawn, + })) + }) } } } @@ -1194,11 +1197,13 @@ impl Position { let aux = |visitor: &mut T, role| { for from in global_mask_from & *ours.get(role) & !pinned { visitor.moves( - (d.targets(role, from, blockers) & !us & target_mask).map(|to| RawMove { - kind: MoveType::PieceMove, - from, - to, - role, + (lookup::targets(role, from, blockers) & !us & target_mask).map(|to| { + RawMove { + kind: MoveType::PieceMove, + from, + to, + role, + } }), ) } @@ -1227,14 +1232,14 @@ impl Position { let aux = |visitor: &mut T, role, pinned_mask| { for from in global_mask_from & *ours.get(role) & pinned_mask { visitor.moves( - (global_mask_to & pinned & !us & d.line(king_square, from)).map(|to| { - RawMove { + (global_mask_to & pinned & !us & lookup::line(king_square, from)).map( + |to| RawMove { kind: MoveType::PieceMove, from, to, role, - } - }), + }, + ), ) } }; diff --git a/src/setup.rs b/src/setup.rs index 718893b..8be10f9 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -4,6 +4,7 @@ use crate::bitboard::*; use crate::board::*; +use crate::lookup; use crate::position::*; /// **A builder type for chess positions.** @@ -346,7 +347,6 @@ impl Setup { debug_assert!((self.p_b_q & self.n_b_k & self.r_q_k).is_empty()); let mut reasons = IllegalPositionReasons::new(); - let d = &crate::lookup::LOOKUP; let blockers = self.p_b_q | self.n_b_k | self.r_q_k; let pieces = self.pieces(); @@ -367,13 +367,13 @@ impl Setup { if pieces.get(!self.turn).king().any(|enemy_king| { let pieces = pieces.get(self.turn); - !(d.king(enemy_king) & *pieces.get(Role::King) - | d.bishop(enemy_king, blockers) + !(lookup::king(enemy_king) & *pieces.get(Role::King) + | lookup::bishop(enemy_king, blockers) & (*pieces.get(Role::Queen) | *pieces.get(Role::Bishop)) - | d.rook(enemy_king, blockers) + | lookup::rook(enemy_king, blockers) & (*pieces.get(Role::Queen) | *pieces.get(Role::Rook)) - | d.knight(enemy_king) & *pieces.get(Role::Knight) - | d.pawn_attack(!self.turn, enemy_king) & *pieces.get(Role::Pawn)) + | lookup::knight(enemy_king) & *pieces.get(Role::Knight) + | lookup::pawn_attack(!self.turn, enemy_king) & *pieces.get(Role::Pawn)) .is_empty() }) { reasons.add(IllegalPositionReason::HangingKing); @@ -449,7 +449,7 @@ impl Setup { .king() .first() .is_some_and(|king_square| { - !(d.bishop(king_square, blockers) + !(lookup::bishop(king_square, blockers) & (pieces.get(!self.turn).queen() | pieces.get(!self.turn).bishop())) .is_empty() })