use std::collections::HashMap; use crate::moves::Move; use super::Grossmeister; /// https://www.chessprogramming.org/Node_Types #[derive(Debug, PartialEq, Clone, Copy)] pub enum NodeType { /// Principal variation node - exact score PV, /// Fail-high Cut, /// Fail-low All, } #[derive(Debug, PartialEq, Clone, Copy)] pub struct TranspositionTableItem { /// Zobrist hash of this position pub hash: u64, pub mov: Option, pub depth: u8, pub score: f32, pub node_type: NodeType, } pub const TTABLE_SIZE: u64 = 2u64.pow(23); #[derive(Debug, Clone)] pub struct TranspositionTable { pub always_replace: HashMap, pub depth_preferred: HashMap, } impl Default for TranspositionTable { fn default() -> Self { TranspositionTable { always_replace: HashMap::with_capacity(TTABLE_SIZE as usize), depth_preferred: HashMap::with_capacity(TTABLE_SIZE as usize), } } } impl Grossmeister { /// Find current position in Transposition Table /// This operation is safe from collisions since it compares the *full* hash pub fn transposition(&self) -> Option<&TranspositionTableItem> { self.transposition_table.depth_preferred.get(&self.board.hash).and_then(|item| { if item.hash == self.board.hash { Some(item) } else { None } }).or(self.transposition_table.always_replace.get(&self.board.hash).and_then(|item| { if item.hash == self.board.hash { Some(item) } else { None } })) } pub fn store_transposition(&mut self, transposition: TranspositionTableItem) { self.transposition_table.always_replace.insert(self.board.hash, transposition); if match self.transposition_table.depth_preferred.get(&self.board.hash) { Some(existing_transposition) => transposition.depth >= existing_transposition.depth, None => true, } { self.transposition_table.depth_preferred.insert(self.board.hash, transposition); } } pub fn table_full(&self) -> u64 { let total_entries = self.transposition_table.always_replace.len() + self.transposition_table.depth_preferred.len(); let total_size = TTABLE_SIZE * 2; (1000.0 * (total_entries as f64 / total_size as f64)) as u64 } }