use std::cmp::min;
use moves::{Move, MoveDigest};
use value::*;
use depth::*;
use search_node::SearchNode;
pub type BoundType = u8;
pub const BOUND_NONE: BoundType = 0;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;
pub trait Ttable: Sync + Send + 'static {
type Entry: TtableEntry;
fn new(size_mb: Option<usize>) -> Self;
fn new_search(&self);
fn store(&self, key: u64, data: Self::Entry);
fn probe(&self, key: u64) -> Option<Self::Entry>;
fn clear(&self);
fn extract_pv<T: SearchNode>(&self, position: &T) -> Variation {
let mut p = position.clone();
let mut our_turn = true;
let mut moves = Vec::with_capacity(32);
let mut root_value = VALUE_UNKNOWN;
let mut value = VALUE_MAX;
let mut bound = BOUND_UPPER;
let mut depth = DEPTH_MAX + 1;
'move_extraction: while let Some(e) = self.probe(p.hash()) {
depth = min(depth - 1, e.depth());
if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
if our_turn {
value = e.value();
bound = e.bound();
} else {
value = -e.value();
bound = match e.bound() {
BOUND_UPPER => BOUND_LOWER,
BOUND_LOWER => BOUND_UPPER,
b => b,
};
}
assert!(value != VALUE_UNKNOWN);
if root_value == VALUE_UNKNOWN {
root_value = value;
}
if depth > 0 &&
match root_value {
v if v < VALUE_EVAL_MIN => {
v as isize == value as isize + moves.len() as isize
}
v if v > VALUE_EVAL_MAX => {
v as isize == value as isize - moves.len() as isize
}
v => v == value,
} {
if let Some(m) = p.try_move_digest(e.move_digest()) {
if p.do_move(m) {
moves.push(m);
if e.bound() == BOUND_EXACT {
our_turn = !our_turn;
continue 'move_extraction;
}
}
}
}
}
break 'move_extraction;
}
Variation {
value: if root_value != VALUE_UNKNOWN {
root_value
} else {
value
},
bound: bound,
moves: moves,
}
}
}
pub trait TtableEntry: Copy + Send + 'static {
fn new(value: Value, bound: BoundType, depth: Depth) -> Self;
fn value(&self) -> Value;
fn bound(&self) -> BoundType;
fn depth(&self) -> Depth;
fn set_move_digest(self, move_digest: MoveDigest) -> Self;
fn move_digest(&self) -> MoveDigest;
#[allow(unused_variables)]
fn set_static_eval(self, static_eval: Value) -> Self {
self
}
fn static_eval(&self) -> Value {
VALUE_UNKNOWN
}
#[inline]
fn importance(&self) -> i16 {
let depth = self.depth() as i16;
match self.bound() {
BOUND_EXACT => depth + 1,
BOUND_NONE => DEPTH_MIN as i16 - 1,
_ => depth,
}
}
}
#[derive(Clone, Debug)]
pub struct Variation {
pub moves: Vec<Move>,
pub value: Value,
pub bound: BoundType,
}