use rand::{rngs::StdRng,SeedableRng,Rng}; use crate::{square::Square, bitboard::BitboardFns}; use super::{Board, Color, Piece, CastlingSide}; const TOTAL_PIECES: usize = 12; const TOTAL_SQUARES: usize = 64; const TOTAL_FILES: usize = 8; const TOTAL_CASTLING_RIGHTS: usize = 4; const ZOBRIST_SEED_SIZE: usize = TOTAL_SQUARES * TOTAL_PIECES + TOTAL_CASTLING_RIGHTS + TOTAL_FILES + 1; pub type ZobristSeed = [u64; ZOBRIST_SEED_SIZE]; pub trait Zobrist { fn seed() -> ZobristSeed; /// Compute store zobrist hash of the current position /// https://www.chessprogramming.org/Zobrist_Hashing fn compute_hash(&mut self) -> (); fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square) -> (); fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide) -> (); fn zobrist_toggle_ep_square(&mut self, ep_square: Square) -> (); fn zobrist_toggle_color(&mut self) -> (); } impl Zobrist for Board { fn seed() -> ZobristSeed { let mut rng = StdRng::seed_from_u64(228); [(); ZOBRIST_SEED_SIZE].map(|_| rng.gen()) } fn compute_hash(&mut self) -> () { self.hash = 0; for piece_id in 0..self.piece_sets.len() { for square in self.piece_sets[piece_id].serialize() { self.zobrist_toggle_piece(Piece::from(piece_id), square); } } for color in [Color::White, Color::Black] { for castle_side in [CastlingSide::King, CastlingSide::Queen] { if self.castling_rights[color as usize][castle_side as usize] { self.zobrist_toggle_castling_right(color, castle_side) } } } match self.ep_target { Some(square) => self.zobrist_toggle_ep_square(square), None => {}, } if self.color() == Color::Black { self.zobrist_toggle_color(); } } fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square) -> () { self.hash ^= self.zobrist_seed[piece_type as usize * TOTAL_SQUARES + square as usize]; } fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide) -> () { self.hash ^= self.zobrist_seed[(TOTAL_PIECES * TOTAL_SQUARES) + color as usize * 2 + side as usize]; } fn zobrist_toggle_ep_square(&mut self, ep_square: Square) -> () { self.hash ^= self.zobrist_seed[(TOTAL_PIECES * TOTAL_SQUARES + TOTAL_CASTLING_RIGHTS) + ep_square.file() as usize]; } fn zobrist_toggle_color(&mut self) -> () { self.hash ^= self.zobrist_seed[ZOBRIST_SEED_SIZE - 1]; } }