|
@@ -19,6 +19,9 @@ pub struct SearchControl<'a> {
|
|
pub pv: Vec<Move>,
|
|
pub pv: Vec<Move>,
|
|
pub killer_moves: Vec<[Move; 2]>,
|
|
pub killer_moves: Vec<[Move; 2]>,
|
|
|
|
|
|
|
|
+ /// current halfmove clock for discarding old hash entries
|
|
|
|
+ pub halfmove_age: u16,
|
|
|
|
+
|
|
/// function to check if the search should be exited
|
|
/// function to check if the search should be exited
|
|
pub check: &'a mut dyn FnMut() -> bool,
|
|
pub check: &'a mut dyn FnMut() -> bool,
|
|
pub stopping: bool,
|
|
pub stopping: bool,
|
|
@@ -40,6 +43,7 @@ impl<'a> SearchControl<'a> {
|
|
nodes: 0,
|
|
nodes: 0,
|
|
pv: Vec::with_capacity(depth as usize),
|
|
pv: Vec::with_capacity(depth as usize),
|
|
killer_moves: vec![[Move::Nullmove; 2]; depth as usize],
|
|
killer_moves: vec![[Move::Nullmove; 2]; depth as usize],
|
|
|
|
+ halfmove_age: 0,
|
|
check,
|
|
check,
|
|
stopping: false,
|
|
stopping: false,
|
|
move_history,
|
|
move_history,
|
|
@@ -127,7 +131,7 @@ pub fn search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alp
|
|
return SearchResult::Cancelled(Some((chosen_mov.0, -chosen_mov.1)));
|
|
return SearchResult::Cancelled(Some((chosen_mov.0, -chosen_mov.1)));
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- hash.cache(game, CacheEntry::new_value(depth, chosen_mov.0, chosen_mov.1));
|
|
|
|
|
|
+ hash.cache(game, CacheEntry::new_value(depth as _, sc.halfmove_age, chosen_mov.0, chosen_mov.1));
|
|
sc.pv[0] = chosen_mov.0;
|
|
sc.pv[0] = chosen_mov.0;
|
|
return SearchResult::Finished(chosen_mov.0, -chosen_mov.1);
|
|
return SearchResult::Finished(chosen_mov.0, -chosen_mov.1);
|
|
}
|
|
}
|
|
@@ -142,7 +146,7 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
|
|
let cache_entry = hash.lookup(game);
|
|
let cache_entry = hash.lookup(game);
|
|
|
|
|
|
if let Some(e) = &cache_entry {
|
|
if let Some(e) = &cache_entry {
|
|
- if e.depth >= depth {
|
|
|
|
|
|
+ if e.depth as i32 >= depth {
|
|
//println!("TABLE HIT!");
|
|
//println!("TABLE HIT!");
|
|
match e.entry_type {
|
|
match e.entry_type {
|
|
EntryType::Value => { return e.value; },
|
|
EntryType::Value => { return e.value; },
|
|
@@ -237,7 +241,7 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
|
|
}
|
|
}
|
|
|
|
|
|
if val >= beta {
|
|
if val >= beta {
|
|
- hash.cache(game, CacheEntry::new_lower(depth, mov, val));
|
|
|
|
|
|
+ hash.cache(game, CacheEntry::new_lower(depth as _, sc.halfmove_age, mov, val));
|
|
if !mov.is_capture() {
|
|
if !mov.is_capture() {
|
|
sc.insert_killer(ply_depth, mov);
|
|
sc.insert_killer(ply_depth, mov);
|
|
}
|
|
}
|
|
@@ -252,12 +256,12 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
|
|
|
|
|
|
|
|
|
|
if alpha_is_exact {
|
|
if alpha_is_exact {
|
|
- hash.cache(game, CacheEntry::new_value(depth, best_move, alpha));
|
|
|
|
|
|
+ hash.cache(game, CacheEntry::new_value(depth as _, sc.halfmove_age, best_move, alpha));
|
|
let cur_depth = (sc.initial_depth - depth) as usize;
|
|
let cur_depth = (sc.initial_depth - depth) as usize;
|
|
sc.pv[cur_depth] = best_move;
|
|
sc.pv[cur_depth] = best_move;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- hash.cache(game, CacheEntry::new_upper(depth, Move::Nullmove, alpha));
|
|
|
|
|
|
+ hash.cache(game, CacheEntry::new_upper(depth as _, sc.halfmove_age, Move::Nullmove, alpha));
|
|
}
|
|
}
|
|
//info!("best alpha {}", alpha);
|
|
//info!("best alpha {}", alpha);
|
|
return alpha;
|
|
return alpha;
|