use crate::engine::attack_table::*;
use crate::game::bit_board::BitBoard;
use rand::Rng;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
const THREAD_COUNT: usize = 10;
const INDEX_SIZE_BITS: usize = 12;
const MAGIC_SHIFT: usize = 64 - INDEX_SIZE_BITS;
const TABLE_SIZE: usize = 1 << INDEX_SIZE_BITS;
pub fn magic_hash(magic_number: u64, occupied_blocking_mask: BitBoard) -> usize {
(occupied_blocking_mask
.get_value()
.wrapping_mul(magic_number)
>> MAGIC_SHIFT) as usize
}
pub fn find_bishop_magics() -> [u64; 64] {
let bishop_blocks = build_bishop_blocks();
let mut bishop_magics = [0u64; 64];
for (square, mask) in bishop_blocks.iter().enumerate() {
let magic = find_magic(square as u8, *mask, calculate_bishop_attack);
bishop_magics[square] = magic;
}
bishop_magics
}
pub fn find_rook_magics() -> [u64; 64] {
let rook_blocks = build_rook_blocks();
let mut rook_magics = [0u64; 64];
for (square, mask) in rook_blocks.iter().enumerate() {
let magic = find_magic(square as u8, *mask, calculate_rook_attack);
rook_magics[square] = magic;
}
rook_magics
}
fn precalculate_attacks(
square: u8,
occupancies: &[BitBoard],
attack_fn: fn(u8, BitBoard) -> BitBoard,
) -> Vec<BitBoard> {
occupancies
.iter()
.map(|occupancy| attack_fn(square, *occupancy))
.collect()
}
fn find_magic(square: u8, block_mask: BitBoard, attack_fn: fn(u8, BitBoard) -> BitBoard) -> u64 {
let occupancies = build_occupancy_variations(block_mask);
let attacks = precalculate_attacks(square, &occupancies, attack_fn);
let occupancy_count = occupancies.len();
(0..THREAD_COUNT)
.into_par_iter()
.find_map_any(|_| {
let mut rng = rand::rng();
let mut table = [None; TABLE_SIZE];
loop {
let magic_number = rng.random::<u64>() & rng.random::<u64>() & rng.random::<u64>();
table.fill(None);
let mut valid = true;
for i in 0..occupancy_count {
let occupancy = occupancies[i];
let attack = attacks[i];
let table_key = magic_hash(magic_number, occupancy);
match table[table_key] {
None => table[table_key] = Some(attack),
Some(existing) if existing != attack => {
valid = false;
break;
}
_ => {}
}
}
if valid {
return Some(magic_number);
}
}
})
.unwrap()
}