use crate::engine::context::SearchContext;
use crate::engine::*;
use crate::state::*;
use crate::utils::assert_fast;
use crate::utils::dev;
use crate::utils::param;
use qsearch::movepick;
use std::cmp;
use std::mem::MaybeUninit;
pub fn run(context: &mut SearchContext, ply: u16, mut alpha: i16, beta: i16) -> i16 {
assert_fast!(alpha <= beta);
assert_fast!(context.board.stm < 2);
context.stats.q_nodes_count += 1;
context.stats.max_ply = cmp::max(ply, context.stats.max_ply);
if context.board.pieces[context.board.stm][KING] == 0 {
dev!(context.stats.q_leafs_count += 1);
return -CHECKMATE_SCORE + (ply as i16);
}
let stand_pat = context.board.evaluate(context.board.stm, &context.phtable, &mut context.stats);
if stand_pat >= beta {
dev!(context.stats.q_leafs_count += 1);
dev!(context.stats.q_beta_cutoffs += 1);
return stand_pat;
}
alpha = cmp::max(alpha, stand_pat);
let mut moves = [MaybeUninit::uninit(); MAX_MOVES_COUNT];
let mut move_scores = [MaybeUninit::uninit(); MAX_MOVES_COUNT];
let moves_count = context.board.get_moves::<true>(&mut moves, 0, u64::MAX);
movepick::assign_move_scores(context, &moves, &mut move_scores, moves_count);
let mut found = false;
for move_index in 0..moves_count {
let (r#move, score) = movesort::sort_next_move(&mut moves, &mut move_scores, move_index, moves_count);
if score_pruning_can_be_applied(context, score) {
dev!(context.stats.q_score_pruning_accepted += 1);
break;
} else {
dev!(context.stats.q_score_pruning_rejected += 1);
}
if futility_pruning_can_be_applied(context, score, stand_pat, alpha) {
dev!(context.stats.q_futility_pruning_accepted += 1);
break;
} else {
dev!(context.stats.q_futility_pruning_rejected += 1);
}
found = true;
context.board.make_move(r#move);
let score = -run(context, ply + 1, -beta, -alpha);
context.board.undo_move(r#move);
alpha = cmp::max(alpha, score);
if alpha >= beta {
dev!(context.stats.q_beta_cutoffs += 1);
if move_index == 0 {
dev!(context.stats.q_perfect_cutoffs += 1);
} else {
dev!(context.stats.q_non_perfect_cutoffs += 1);
}
break;
}
}
if !found {
dev!(context.stats.q_leafs_count += 1);
}
alpha
}
fn score_pruning_can_be_applied(context: &SearchContext, move_score: i16) -> bool {
move_score < param!(context.params.q_score_pruning_treshold)
}
fn futility_pruning_can_be_applied(context: &SearchContext, move_score: i16, stand_pat: i16, alpha: i16) -> bool {
stand_pat + move_score + param!(context.params.q_futility_pruning_margin) < alpha
}