use std::sync::LazyLock;
use crate::piece::Piece;
use crate::square::Square;
use crate::util::Rc4;
use crate::util::SplitMix64;
pub struct ZobristTables {
pub key_piece: [[u64; Square::COUNT]; Piece::COUNT],
pub lock_piece: [[u32; Square::COUNT]; Piece::COUNT],
pub key_stm: u64,
pub lock_stm: u32,
}
pub static ZOBRIST: LazyLock<ZobristTables> = LazyLock::new(build);
const BOOK_MAILBOX_STRIDE: u8 = 16;
const BOOK_RANK_TOP: u8 = 12;
const BOOK_FILE_OFFSET: u8 = 3;
fn build() -> ZobristTables {
let mut rc4 = Rc4::new(&[0]);
let _ = rc4.next_u32(); let _ = rc4.next_u32();
let lock_stm = rc4.next_u32();
let mut lock_mailbox = [[0u32; 256]; Piece::COUNT];
for row in lock_mailbox.iter_mut() {
for slot in row.iter_mut() {
let _ = rc4.next_u32(); let _ = rc4.next_u32();
*slot = rc4.next_u32();
}
}
let mut lock_piece = [[0u32; Square::COUNT]; Piece::COUNT];
for color in 0..2 {
for kind in 0..7 {
let piece_idx = color * 7 + kind;
for sq in 0..Square::COUNT as u8 {
let rank = sq / 9;
let file = sq % 9;
let book_rank = BOOK_RANK_TOP - rank;
let book_file = file + BOOK_FILE_OFFSET;
let book_mailbox = (book_rank * BOOK_MAILBOX_STRIDE + book_file) as usize;
lock_piece[piece_idx][sq as usize] = lock_mailbox[piece_idx][book_mailbox];
}
}
}
let mut rng = SplitMix64::new(0xA1B2_C3D4_E5F6_0718);
let key_stm = rng.next_u64();
let mut key_piece = [[0u64; Square::COUNT]; Piece::COUNT];
for row in key_piece.iter_mut() {
for slot in row.iter_mut() {
*slot = rng.next_u64();
}
}
ZobristTables { key_piece, lock_piece, key_stm, lock_stm }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tables_populated() {
let t = &*ZOBRIST;
let mut zero_keys = 0usize;
for row in &t.key_piece {
for v in row {
if *v == 0 {
zero_keys += 1;
}
}
}
assert!(zero_keys < 4, "zero-key entries should be rare: {zero_keys}");
assert_ne!(t.key_stm, 0);
assert_ne!(t.lock_stm, 0);
}
}