mod factors;
use factors::*;
use crate::bitboard::*;
use crate::board::*;
use crate::util::*;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Magic {
pub premask: Bitboard,
pub factor: u64,
pub offset: isize,
}
#[allow(dead_code)]
pub(crate) fn build() -> (Vec<Magic>, Vec<u64>) {
let mut magics: Vec<Magic> = Vec::new();
let mut table: Vec<u64> = Vec::new();
for (shr, factor_fn, premask_fn, dirs) in [
(
BISHOP_SHR,
bishop_factor as fn(Square) -> u64,
bishop_premask as fn(Square) -> Bitboard,
[
Direction::NorthEast,
Direction::NorthWest,
Direction::SouthWest,
Direction::SouthEast,
],
),
(
ROOK_SHR,
rook_factor as fn(Square) -> u64,
rook_premask as fn(Square) -> Bitboard,
[
Direction::East,
Direction::North,
Direction::West,
Direction::South,
],
),
] {
for square in Square::all() {
let factor = factor_fn(square);
let premask = premask_fn(square);
let mut gap = isize::MAX;
loop_subsets(!premask, |blockers| {
gap = gap.min(hash(shr, factor, blockers | premask) as isize);
});
let offset = table.len() as isize - gap;
loop_subsets(!premask, |blockers| {
let idx = hash(shr, factor, blockers | premask) as isize + offset;
let idx = idx as usize;
while table.len() <= idx {
table.push(0);
}
let mut value = 0;
for dir in dirs {
value |= blocked_ray(square, dir, blockers).0;
}
assert!(table[idx] == 0 || table[idx] == value);
table[idx] = value;
});
magics.push(Magic {
premask,
factor,
offset,
});
}
}
(magics, table)
}
#[inline]
fn loop_subsets<F>(premask: Bitboard, mut f: F)
where
F: FnMut(Bitboard),
{
let mut blockers: u64 = 0;
loop {
blockers = blockers.wrapping_sub(premask.0) & premask.0;
f(Bitboard(blockers));
if blockers == 0 {
break;
}
}
}
#[inline]
const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -> Bitboard {
let r = ray(square, direction);
let blockers = Bitboard(blockers.0 & r.0);
let square = if (direction as u8) < 4 {
Bitboard::first(&blockers)
} else {
Bitboard::last(&blockers)
};
match square {
None => r,
Some(square) => Bitboard(r.0 & !ray(square, direction).0),
}
}
fn bishop_premask(square: Square) -> Bitboard {
let mut premask = Bitboard::new();
for dir in [
Direction::NorthEast,
Direction::NorthWest,
Direction::SouthWest,
Direction::SouthEast,
] {
premask |= ray(square, dir);
}
premask &= !Rank::First.bitboard();
premask &= !Rank::Eighth.bitboard();
premask &= !File::A.bitboard();
premask &= !File::H.bitboard();
!premask
}
fn rook_premask(square: Square) -> Bitboard {
let mut premask = Bitboard::new();
premask |= ray(square, Direction::East) & !File::H.bitboard();
premask |= ray(square, Direction::North) & !Rank::Eighth.bitboard();
premask |= ray(square, Direction::West) & !File::A.bitboard();
premask |= ray(square, Direction::South) & !Rank::First.bitboard();
!premask
}