Add magic bitboard generation

This commit is contained in:
Bruno BELANYI 2022-07-22 18:42:05 +02:00
parent 5ef3737b98
commit 066d442823
4 changed files with 75 additions and 3 deletions

View file

@ -14,7 +14,6 @@ pub struct Magic {
impl Magic { impl Magic {
/// Compute the index into the magics database for this set of `blockers`. /// Compute the index into the magics database for this set of `blockers`.
#[allow(unused)] // FIXME: remove once used
pub fn get_index(&self, blockers: Bitboard) -> usize { pub fn get_index(&self, blockers: Bitboard) -> usize {
let relevant_occupancy = (blockers & self.mask).0; let relevant_occupancy = (blockers & self.mask).0;
let base_index = ((relevant_occupancy.wrapping_mul(self.magic)) >> self.shift) as usize; let base_index = ((relevant_occupancy.wrapping_mul(self.magic)) >> self.shift) as usize;

View file

@ -0,0 +1,74 @@
use crate::board::{Bitboard, Square};
use crate::movegen::bishop::bishop_moves;
use crate::movegen::rook::rook_moves;
use crate::movegen::Magic;
use super::mask::{generate_bishop_mask, generate_rook_mask};
/// A trait to represent RNG for u64 values.
#[allow(unused)] // FIXME: remove when used
pub(crate) trait RandGen {
fn gen(&mut self) -> u64;
}
type MagicGenerationType = (Vec<Magic>, Vec<Bitboard>);
#[allow(unused)] // FIXME: remove when used
pub fn generate_bishop_magics(rng: &mut dyn RandGen) -> MagicGenerationType {
generate_magics(rng, generate_bishop_mask, bishop_moves)
}
#[allow(unused)] // FIXME: remove when used
pub fn generate_rook_magics(rng: &mut dyn RandGen) -> MagicGenerationType {
generate_magics(rng, generate_rook_mask, rook_moves)
}
fn generate_magics(
rng: &mut dyn RandGen,
mask_fn: impl Fn(Square) -> Bitboard,
moves_fn: impl Fn(Square, Bitboard) -> Bitboard,
) -> MagicGenerationType {
let mut magics = Vec::new();
let mut boards = Vec::new();
for square in Square::iter() {
let mask = mask_fn(square);
let occupancy_to_moves: Vec<_> = mask
.iter_power_set()
.map(|occupancy| (occupancy, moves_fn(square, occupancy)))
.collect();
'candidate_search: loop {
let mut candidate = Magic {
magic: magic_candidate(rng),
offset: 0,
mask,
shift: (64 - mask.count()) as u8,
};
let mut candidate_moves = vec![Bitboard::EMPTY; occupancy_to_moves.len()];
for (occupancy, moves) in occupancy_to_moves.iter().cloned() {
let index = candidate.get_index(occupancy);
// Non-constructive collision, try with another candidate
if !candidate_moves[index].is_empty() && candidate_moves[index] != moves {
continue 'candidate_search;
}
candidate_moves[index] = moves;
}
// We have filled all candidate boards, record the correct offset and add the moves
candidate.offset = boards.len();
magics.push(candidate);
boards.append(&mut candidate_moves);
break;
}
}
(magics, boards)
}
fn magic_candidate(rng: &mut dyn RandGen) -> u64 {
// Few bits makes for better candidates
rng.gen() & rng.gen() & rng.gen()
}

View file

@ -3,7 +3,6 @@ use crate::movegen::bishop::bishop_moves;
use crate::movegen::rook::rook_moves; use crate::movegen::rook::rook_moves;
/// Compute the relevancy mask for a bishop on a given [Square]. /// Compute the relevancy mask for a bishop on a given [Square].
#[allow(unused)] // FIXME: remove once used
pub fn generate_bishop_mask(square: Square) -> Bitboard { pub fn generate_bishop_mask(square: Square) -> Bitboard {
let rays = bishop_moves(square, Bitboard::EMPTY); let rays = bishop_moves(square, Bitboard::EMPTY);
@ -16,7 +15,6 @@ pub fn generate_bishop_mask(square: Square) -> Bitboard {
} }
/// Compute the relevancy mask for a rook on a given [Square]. /// Compute the relevancy mask for a rook on a given [Square].
#[allow(unused)] // FIXME: remove once used
pub fn generate_rook_mask(square: Square) -> Bitboard { pub fn generate_rook_mask(square: Square) -> Bitboard {
let rays = rook_moves(square, Bitboard::EMPTY); let rays = rook_moves(square, Bitboard::EMPTY);

View file

@ -1 +1,2 @@
mod generation;
mod mask; mod mask;