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)] struct TranspositionTable { table: Vec>, } impl Default for TranspositionTable { fn default() -> Self { Self { table: vec![None; TTABLE_SIZE as usize] } } } impl TranspositionTable { fn set(&mut self, hash: u64, item: TranspositionTableItem) { self.table[(hash % TTABLE_SIZE) as usize] = Some(item); } /// This operation is safe from collisions since it compares the *full* hash /// TODO: only compare the other half of the hash fn get(&self, hash: u64) -> Option<&TranspositionTableItem> { self.table[(hash % TTABLE_SIZE) as usize].as_ref().and_then(|item| { if item.hash == hash { Some(item) } else { None } }) } fn len(&self) -> usize { self.table.iter().filter(|item| item.is_some()).count() } } #[derive(Debug, Default, Clone)] pub struct MasterTable { always_replace: TranspositionTable, depth_preferred: TranspositionTable, } impl Grossmeister { pub fn transposition(&self) -> Option<&TranspositionTableItem> { self.transposition_table.depth_preferred.get(self.board.hash) .or(self.transposition_table.always_replace.get(self.board.hash)) } pub fn store_transposition(&mut self, transposition: TranspositionTableItem) { self.transposition_table.always_replace.set(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.set(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 } }