use crate::prelude::*;
use crate::hash::Key;
use crate::misc::Prng;
#[allow(missing_debug_implementations)]
#[must_use]
pub struct Zobrist {
psq: [[Key; Square::COUNT]; Piece::COUNT],
en_passant: [Key; File::COUNT],
castling: [Key; CastlingRights::COUNT],
side: Key,
no_pawns: Key,
}
impl Zobrist {
const PRNG_SEED: u64 = 1_070_372;
pub(crate) const fn new() -> Self {
let mut prng = Prng::from(Self::PRNG_SEED);
let mut psq = [[Key::default(); Square::COUNT]; Piece::COUNT];
let mut en_passant = [Key::default(); File::COUNT];
let mut castling = [Key::default(); CastlingRights::COUNT];
let mut i;
let mut j;
i = 0;
while i < Piece::COUNT {
j = 0;
while j < Square::COUNT {
psq[i][j] = prng.next_u64().into();
j += 1;
}
i += 1;
}
i = 0;
while i < File::COUNT {
en_passant[i] = prng.next_u64().into();
i += 1;
}
i = 0;
while i < CastlingRights::COUNT {
castling[i] = prng.next_u64().into();
i += 1;
}
Self {
psq,
en_passant,
castling,
side: prng.next_u64().into(),
no_pawns: prng.next_u64().into(),
}
}
#[inline]
pub const fn piece_square_key(&self, piece: Piece, square: Square) -> Key {
self.psq[piece][square]
}
#[inline]
pub const fn en_passant_key(&self, file: File) -> Key {
self.en_passant[file]
}
#[inline]
pub const fn castling_key(&self, castling: CastlingRights) -> Key {
self.castling[castling.bits() as usize]
}
#[inline]
pub const fn side_key(&self) -> Key {
self.side
}
#[inline]
pub const fn no_pawns_key(&self) -> Key {
self.no_pawns
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn test_all_keys_unique() {
let mut set = HashSet::new();
let zobrist = Zobrist::new();
for piece in Piece::iter() {
for square in Square::iter() {
assert!(set.insert(zobrist.piece_square_key(piece, square)));
}
}
for file in File::iter() {
assert!(set.insert(zobrist.en_passant_key(file)));
}
for castling in CastlingRights::iter() {
assert!(set.insert(zobrist.castling_key(castling)));
}
assert!(set.insert(zobrist.side_key()));
assert!(set.insert(zobrist.no_pawns_key()));
}
}