|
@@ -11,6 +11,7 @@ pub struct SearchControl<'a> {
|
|
pub nodes: usize,
|
|
pub nodes: usize,
|
|
|
|
|
|
pub pv: Vec<Move>,
|
|
pub pv: Vec<Move>,
|
|
|
|
+ pub killer_moves: [Move; 3],
|
|
|
|
|
|
/// 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,
|
|
@@ -33,12 +34,24 @@ impl<'a> SearchControl<'a> {
|
|
SearchControl {
|
|
SearchControl {
|
|
nodes: 0,
|
|
nodes: 0,
|
|
pv: Vec::with_capacity(depth as usize),
|
|
pv: Vec::with_capacity(depth as usize),
|
|
|
|
+ killer_moves: [Move::Nullmove; 3],
|
|
check,
|
|
check,
|
|
stopping: false,
|
|
stopping: false,
|
|
move_history,
|
|
move_history,
|
|
initial_depth: depth
|
|
initial_depth: depth
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ pub fn insert_killer(&mut self, killer: Move) {
|
|
|
|
+ for i in 1..self.killer_moves.len() {
|
|
|
|
+ self.killer_moves[i - 1] = self.killer_moves[i];
|
|
|
|
+ }
|
|
|
|
+ self.killer_moves[self.killer_moves.len() - 1] = killer;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn is_killer(&self, killer: &Move) -> bool {
|
|
|
|
+ self.killer_moves.contains(killer)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -52,7 +65,7 @@ pub fn search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut alp
|
|
|
|
|
|
let mut moves = generate_legal_moves(game, game.turn);
|
|
let mut moves = generate_legal_moves(game, game.turn);
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
- sort_moves(game, hash, &mut moves);
|
|
|
|
|
|
+ sort_moves(game, hash, &sc.killer_moves, &mut moves);
|
|
|
|
|
|
info!("moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
|
|
info!("moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
|
|
|
|
|
|
@@ -191,7 +204,8 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- sort_moves(game, hash, &mut moves);
|
|
|
|
|
|
+ sort_moves(game, hash, &sc.killer_moves, &mut moves);
|
|
|
|
+ //moves.sort_by_cached_key(|m| if sc.is_killer(*m) { -1 } else { 0 });
|
|
|
|
|
|
let mut alpha_is_exact = false;
|
|
let mut alpha_is_exact = false;
|
|
let mut best_move = Move::Nullmove;
|
|
let mut best_move = Move::Nullmove;
|
|
@@ -217,6 +231,7 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
|
|
hash.cache(game, CacheEntry::new_upper(depth, val));
|
|
hash.cache(game, CacheEntry::new_upper(depth, val));
|
|
//println!("but ret {}: {}", depth, beta);
|
|
//println!("but ret {}: {}", depth, beta);
|
|
//info!("{} causes beta cutoff at {} ", mov.to_string(), val);
|
|
//info!("{} causes beta cutoff at {} ", mov.to_string(), val);
|
|
|
|
+ sc.insert_killer(mov);
|
|
return beta;
|
|
return beta;
|
|
}
|
|
}
|
|
if increase_mate_in(val) > alpha {
|
|
if increase_mate_in(val) > alpha {
|
|
@@ -269,7 +284,7 @@ fn quiescence_search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache,
|
|
|
|
|
|
for mov in moves {
|
|
for mov in moves {
|
|
let undo = game.apply(mov);
|
|
let undo = game.apply(mov);
|
|
- let mut val = -quiescence_search(game, sc, hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1);
|
|
|
|
|
|
+ let val = -quiescence_search(game, sc, hash, decrease_mate_in(-beta), decrease_mate_in(-alpha), depth - 1);
|
|
game.undo_move(undo);
|
|
game.undo_move(undo);
|
|
|
|
|
|
if sc.stopping {
|
|
if sc.stopping {
|