use std::ptr::NonNull;
use crate::nnue::{DirtyPiece, ensure_accumulator_computed, evaluate_dispatch};
use crate::position::Position;
use crate::prefetch::TtPrefetch;
use crate::search::PieceToHistory;
use crate::types::{Move, Piece, Square, Value};
use super::alpha_beta::{SearchContext, SearchState};
use super::types::{ContHistKey, STACK_SIZE};
use super::{LimitsType, TimeManagement};
#[inline]
pub(super) fn check_abort(
st: &mut SearchState,
ctx: &SearchContext<'_>,
limits: &LimitsType,
time_manager: &mut TimeManagement,
) -> bool {
if st.abort {
#[cfg(debug_assertions)]
eprintln!("check_abort: abort flag already set");
return true;
}
st.calls_cnt -= 1;
if st.calls_cnt > 0 {
return false;
}
st.calls_cnt = if limits.nodes > 0 {
std::cmp::min(512, (limits.nodes / 1024) as i32).max(1)
} else {
512
};
if time_manager.stop_requested() {
#[cfg(debug_assertions)]
eprintln!("check_abort: stop requested");
st.abort = true;
return true;
}
if limits.nodes > 0 && st.nodes >= limits.nodes {
#[cfg(debug_assertions)]
eprintln!("check_abort: node limit reached nodes={} limit={}", st.nodes, limits.nodes);
st.abort = true;
return true;
}
if ctx.thread_id == 0 {
if time_manager.take_ponderhit() {
time_manager.on_ponderhit();
}
let elapsed = time_manager.elapsed();
let elapsed_effective = time_manager.elapsed_from_ponderhit();
if time_manager.search_end() > 0 && elapsed >= time_manager.search_end() {
#[cfg(debug_assertions)]
eprintln!(
"check_abort: search_end reached elapsed={} search_end={}",
elapsed,
time_manager.search_end()
);
st.abort = true;
return true;
}
if !time_manager.is_pondering()
&& time_manager.search_end() == 0
&& limits.use_time_management()
&& (elapsed_effective > time_manager.maximum() || time_manager.stop_on_ponderhit())
{
time_manager.set_search_end(elapsed);
}
}
false
}
#[inline]
pub(super) fn nnue_evaluate(st: &mut SearchState, pos: &Position) -> Value {
evaluate_dispatch(pos, &mut st.nnue_stack)
}
#[inline]
pub(super) fn ensure_nnue_accumulator(st: &mut SearchState, pos: &Position) {
ensure_accumulator_computed(pos, &mut st.nnue_stack)
}
#[inline]
pub(super) fn do_move_and_push<P: TtPrefetch>(
st: &mut SearchState,
pos: &mut Position,
mv: Move,
gives_check: bool,
prefetcher: &P,
) {
let dirty_piece = pos.do_move_with_prefetch(mv, gives_check, prefetcher);
st.nodes += 1;
st.nnue_stack.push(dirty_piece);
}
#[inline]
pub(super) fn nnue_push(st: &mut SearchState, dirty_piece: DirtyPiece) {
st.nnue_stack.push(dirty_piece);
}
#[inline]
pub(super) fn nnue_pop(st: &mut SearchState) {
st.nnue_stack.pop();
}
#[inline]
pub(super) fn cont_history_ptr(
st: &SearchState,
ctx: &SearchContext<'_>,
ply: i32,
back: i32,
) -> NonNull<PieceToHistory> {
debug_assert!(ply >= 0 && (ply as usize) < STACK_SIZE, "ply out of bounds: {ply}");
debug_assert!(back >= 0, "back must be non-negative: {back}");
if ply >= back {
st.stack[(ply - back) as usize].cont_history_ptr
} else {
ctx.cont_history_sentinel
}
}
#[inline]
pub(super) fn cont_history_ref<'a>(
st: &'a SearchState,
ctx: &SearchContext<'_>,
ply: i32,
back: i32,
) -> &'a PieceToHistory {
let ptr = cont_history_ptr(st, ctx, ply, back);
unsafe { ptr.as_ref() }
}
#[inline]
pub(super) fn cont_history_tables<'a>(
st: &'a SearchState,
ctx: &SearchContext<'_>,
ply: i32,
) -> [&'a PieceToHistory; 6] {
[
cont_history_ref(st, ctx, ply, 1),
cont_history_ref(st, ctx, ply, 2),
cont_history_ref(st, ctx, ply, 3),
cont_history_ref(st, ctx, ply, 4),
cont_history_ref(st, ctx, ply, 5),
cont_history_ref(st, ctx, ply, 6),
]
}
#[inline]
pub(super) fn set_cont_history_for_move(
st: &mut SearchState,
ctx: &SearchContext<'_>,
ply: i32,
in_check: bool,
capture: bool,
piece: Piece,
to: Square,
) {
debug_assert!(ply >= 0 && (ply as usize) < STACK_SIZE, "ply out of bounds: {ply}");
let in_check_idx = in_check as usize;
let capture_idx = capture as usize;
let table = {
let h = unsafe { ctx.history.as_ref_unchecked() };
NonNull::from(h.continuation_history[in_check_idx][capture_idx].get_table(piece, to))
};
st.stack[ply as usize].cont_history_ptr = table;
st.stack[ply as usize].cont_hist_key = Some(ContHistKey::new(in_check, capture, piece, to));
}
#[inline]
pub(super) fn clear_cont_history_for_null(st: &mut SearchState, ctx: &SearchContext<'_>, ply: i32) {
st.stack[ply as usize].cont_history_ptr = ctx.cont_history_sentinel;
st.stack[ply as usize].cont_hist_key = Some(ContHistKey::null_sentinel());
}
#[inline]
pub(super) fn take_prior_reduction(st: &mut SearchState, ply: i32) -> i32 {
if ply >= 1 {
let parent_idx = (ply - 1) as usize;
let pr = st.stack[parent_idx].reduction;
st.stack[parent_idx].reduction = 0;
pr
} else {
0
}
}