aboutsummaryrefslogtreecommitdiff
path: root/src/grossmeister/search.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/grossmeister/search.rs')
-rw-r--r--src/grossmeister/search.rs66
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());