diff options
Diffstat (limited to 'src/grossmeister/search.rs')
-rw-r--r-- | src/grossmeister/search.rs | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/src/grossmeister/search.rs b/src/grossmeister/search.rs index 3efa9f8..ff6375c 100644 --- a/src/grossmeister/search.rs +++ b/src/grossmeister/search.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::{time::{Instant, Duration}, f32::INFINITY}; use crate::{moves::{Move, MoveKind}, board::io::IO}; @@ -48,7 +49,7 @@ impl Grossmeister { return (self.quiscence(alpha, beta), principal_variation); } - let mut moves = self.generate_pseudolegal_moves(); + let mut moves = self.board.generate_pseudolegal_moves(); moves = self.order_moves(moves, parent_killers.to_vec()); let mut should_pv_search = true; @@ -141,7 +142,7 @@ impl Grossmeister { pub fn quiscence(&mut self, mut alpha: f32, beta: f32) -> f32 { let color = self.board.color(); - let mut moves = self.generate_pseudolegal_moves(); + let mut moves = self.board.generate_pseudolegal_moves(); moves = self.order_moves(moves, Vec::new()); if !self.board.is_king_in_check(color) { @@ -259,6 +260,65 @@ impl Grossmeister { } } + /// Evaluate move for move ordering, prioritizing efficient captures + /// where low-value pieces capture high-value pieces + fn eval_move(&self, m: Move) -> f32 { + if m.is_tactical() { + let [source_eval, target_eval] = [m.source, m.target] + .map(|sq| self.board.piece_by_square(sq)) + .map(|p| { + match p { + Some(p) => p.static_eval(), + None => 0., + } + }); + return 2. * target_eval - source_eval + } + 0.0 + } + + pub fn order_moves(&self, moves: Vec<Move>, killer_moves: Vec<Move>) -> Vec<Move> { + let mut moves_with_eval: Vec<(Move, f32)> = moves + .iter() + .map(|m| (*m, self.eval_move(*m))) + .collect(); + + moves_with_eval.sort_unstable_by(|(a, a_eval), (b, b_eval)| { + if *a_eval == 0.0 && *b_eval == 0.0 { + // Prioritize equal captures over non-captures + if a.is_tactical() && !b.is_tactical() { + return Ordering::Less + } + if b.is_tactical() && !a.is_tactical() { + return Ordering::Greater + } + } + a_eval.total_cmp(b_eval).reverse() + }); + + let mut ordered_moves: Vec<Move> = moves_with_eval.iter().map(|(m, _)| *m).collect(); + + // Insert killer moves after winning captures + let equal_capture_index = moves_with_eval + .iter() + .position(|(m, eval)| m.is_tactical() && *eval == 0.0) + .unwrap_or(0); + + for killer in killer_moves { + if let Some(index) = ordered_moves.iter().position(|m| *m == killer) { + let mov = ordered_moves.remove(index); + ordered_moves.insert(equal_capture_index, mov); + } + } + + if let Some(transposition) = self.transposition() { + ordered_moves.insert(0, transposition.mov); + } + + ordered_moves + } + + pub fn perft(&mut self, depth: u8, print: bool) -> PerftResult { let mut result = PerftResult::default(); @@ -268,7 +328,7 @@ impl Grossmeister { } let color = self.board.color(); - let moves = self.generate_pseudolegal_moves(); + let moves = self.board.generate_pseudolegal_moves(); if print { println!("Running perft for depth {}. Color to move is {:?}\n{} moves available", depth, color, moves.len()); |