use std::cmp::Ordering; 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, } impl NodeType { fn cmp_order(&self) -> u8 { match self { NodeType::PV => 2, NodeType::Cut => 1, NodeType::All => 0, } } } impl PartialOrd for NodeType { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp_order().cmp(&other.cmp_order())) } } #[derive(Debug, PartialEq, Clone, Copy)] pub struct TranspositionTableItem { /// Zobrist hash of this position pub hash: u64, pub mov: Move, pub depth: u8, pub score: f32, pub node_type: NodeType, } impl PartialOrd for TranspositionTableItem { fn partial_cmp(&self, other: &Self) -> Option { // Order by depth first, then node type let depth_ordering = self.depth.partial_cmp(&other.depth); match depth_ordering { Some(Ordering::Equal) => self.node_type.partial_cmp(&other.node_type), _ => depth_ordering, } } } pub const TTABLE_SIZE: u64 = 2u64.pow(24); pub type TranspositionTable = Vec>; impl Grossmeister { fn transposition_ref(&mut self) -> &mut Option { &mut self.transposition_table[(self.board.hash % TTABLE_SIZE) as usize] } /// Find current position in Transposition Table /// This operation is safe from collisions since it compares the *full* hash pub fn transposition(&mut self) -> Option { let hash = self.board.hash; match self.transposition_ref() { Some(item) => { if item.hash == hash { return Some(*item) } None } None => None } } pub fn store_transposition(&mut self, transposition: TranspositionTableItem) { let transposition_ref = self.transposition_ref(); match transposition_ref { Some(existing_transposition) => { if transposition >= *existing_transposition { *transposition_ref = Some(transposition) } } None => *transposition_ref = Some(transposition) } } }