From 884c90386ef2e293cea7787c62790c06ac9a73dd Mon Sep 17 00:00:00 2001 From: Adarsh Das Date: Wed, 27 May 2026 12:06:49 +0530 Subject: [PATCH] Move cutoff_count and excluded from StackEntry, and change move_count for 32b align VSTC (non-reg, field removal) Elo | 1.21 +- 1.89 (95%) SPRT | 4.0+0.04s Threads=1 Hash=16MB LLR | 3.06 (-2.25, 2.89) [-2.75, 0.25] Games | N: 34278 W: 8853 L: 8734 D: 16691 Penta | [171, 3772, 9143, 3873, 180] https://recklesschess.space/test/15023/ VSTC (gainer with 32b align) Elo | 2.16 +- 1.56 (95%) SPRT | 4.0+0.04s Threads=1 Hash=16MB LLR | 3.36 (-2.25, 2.89) [0.00, 3.00] Games | N: 49774 W: 13059 L: 12750 D: 23965 Penta | [263, 5286, 13490, 5575, 273] https://recklesschess.space/test/15024/ Bench: 3479389 Co-authored By: Shahin M. Shahin --- src/search.rs | 29 ++++++++++++++++------------- src/stack.rs | 6 +----- src/thread.rs | 36 +++++++++++++++++++++++++++++++++--- src/types/moves.rs | 6 ++++++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/search.rs b/src/search.rs index ffc7b8262..5a089e7a4 100644 --- a/src/search.rs +++ b/src/search.rs @@ -4,7 +4,7 @@ use crate::{ evaluation::correct_eval, movepick::{MovePicker, Stage}, stack::Stack, - thread::{RootMove, Status, ThreadData}, + thread::{PlyArray, RootMove, Status, ThreadData}, time::Limits, transposition::{Bound, TtDepth}, types::{ @@ -125,6 +125,8 @@ pub fn start(td: &mut ThreadData, report: Report, thread_count: usize) { loop { td.stack = Stack::new(); + td.cutoff_count = PlyArray::default(); + td.excluded = PlyArray::default(); td.root_delta = beta - alpha; // Root Search @@ -269,7 +271,7 @@ fn search( let stm = td.board.side_to_move(); let in_check = td.board.in_check(); - let excluded = td.stack[ply].excluded.is_present(); + let excluded = td.excluded[ply].is_present(); if !NODE::ROOT && NODE::PV { td.pv_table.clear(ply as usize); @@ -448,7 +450,7 @@ fn search( td.stack[ply].tt_pv = tt_pv; td.stack[ply].reduction = 0; td.stack[ply].move_count = 0; - td.stack[ply + 2].cutoff_count = 0; + td.cutoff_count[ply + 2] = 0; // Quiet move ordering using eval difference if !NODE::ROOT && !in_check && !excluded && td.stack[ply - 1].mv.is_quiet() && is_valid(td.stack[ply - 1].eval) { @@ -528,7 +530,7 @@ fn search( >= beta + (-9 * depth + 108 * tt_pv as i32 - 96 * improvement / 1024 - - 18 * (td.stack[ply + 1].cutoff_count < 2) as i32 + - 18 * (td.cutoff_count[ply + 1] < 2) as i32 + 320) .max(2) && ply as i32 >= td.nmp_min_ply @@ -600,7 +602,7 @@ fn search( break; } - if mv == td.stack[ply].excluded { + if mv == td.excluded[ply] { continue; } @@ -653,10 +655,10 @@ fn search( let singular_beta = tt_score - singular_margin; let singular_depth = (depth - 1) / 2; - td.stack[ply].excluded = tt_move; + td.excluded[ply] = tt_move; td.stack[ply].mv = Move::NULL; singular_score = search::(td, singular_beta - 1, singular_beta, singular_depth, cut_node, ply); - td.stack[ply].excluded = Move::NULL; + td.excluded[ply] = Move::NULL; td.stack[ply].tt_pv = tt_pv; if td.shared.status.get() == Status::STOPPED { @@ -705,7 +707,7 @@ fn search( let mut tt_move_score = Score::NONE; while let Some(mv) = move_picker.next::(td, skip_quiets, ply) { - if mv == td.stack[ply].excluded { + if mv == td.excluded[ply] { continue; } @@ -732,7 +734,8 @@ fn search( && !td.board.is_direct_check(mv) && is_quiet && !is_win(beta) - && move_count >= (2697 + 77 * improvement / 16 + 1510 * depth * depth + 70 * history / 1024) / 1024 + && move_count as i32 + >= (2697 + 77 * improvement / 16 + 1510 * depth * depth + 70 * history / 1024) / 1024 { skip_quiets = true; continue; @@ -838,7 +841,7 @@ fn search( reduction -= 939; } - if td.stack[ply + 1].cutoff_count > 2 { + if td.cutoff_count[ply + 1] > 2 { reduction += 992; reduction += 384 * (!NODE::PV && !cut_node) as i32; } @@ -901,7 +904,7 @@ fn search( reduction += (402 - 232 * improvement / 128).min(1426); } - if td.stack[ply + 1].cutoff_count > 2 { + if td.cutoff_count[ply + 1] > 2 { reduction += 1454; reduction += 256 * (!NODE::PV && !cut_node) as i32; } @@ -995,7 +998,7 @@ fn search( if score >= beta { bound = Bound::Lower; - td.stack[ply].cutoff_count += 1; + td.cutoff_count[ply] += 1; break; } @@ -1074,7 +1077,7 @@ fn search( let prior_move = td.stack[ply - 1].mv; if prior_move.is_quiet() { let factor = 88 - + (17 * td.stack[ply - 1].move_count).min(229) + + (17 * td.stack[ply - 1].move_count as i32).min(229) + 110 * (prior_move == td.stack[ply - 1].tt_move) as i32 + 144 * (!in_check && best_score <= eval - 97) as i32 + 306 * (is_valid(td.stack[ply - 1].eval) && best_score <= -td.stack[ply - 1].eval - 136) as i32; diff --git a/src/stack.rs b/src/stack.rs index 77b85c9e3..56baccd42 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -37,11 +37,9 @@ pub struct StackEntry { pub mv: Move, pub piece: Piece, pub eval: i32, - pub excluded: Move, pub tt_move: Move, pub tt_pv: bool, - pub cutoff_count: i32, - pub move_count: i32, + pub move_count: u16, pub reduction: i32, pub conthist: *mut [[i16; 64]; 13], pub contcorrhist: *mut [[i16; 64]; 13], @@ -55,10 +53,8 @@ impl Default for StackEntry { mv: Move::NULL, piece: Piece::None, eval: Score::NONE, - excluded: Move::NULL, tt_move: Move::NULL, tt_pv: false, - cutoff_count: 0, move_count: 0, reduction: 0, conthist: std::ptr::null_mut(), diff --git a/src/thread.rs b/src/thread.rs index fbde4f495..729cb1d98 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,6 +1,9 @@ -use std::sync::{ - Arc, - atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicUsize, Ordering}, +use std::{ + ops::{Index, IndexMut}, + sync::{ + Arc, + atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicUsize, Ordering}, + }, }; use crate::{ @@ -132,6 +135,29 @@ impl Default for SharedContext { } } +pub struct PlyArray { + data: [T; N], +} + +impl Index for PlyArray { + type Output = T; + fn index(&self, index: isize) -> &T { + &self.data[(index + 8) as usize] + } +} + +impl IndexMut for PlyArray { + fn index_mut(&mut self, index: isize) -> &mut T { + &mut self.data[(index + 8) as usize] + } +} + +impl Default for PlyArray { + fn default() -> Self { + Self { data: [T::default(); N] } + } +} + pub struct ThreadData { pub id: usize, pub shared: Arc, @@ -158,6 +184,8 @@ pub struct ThreadData { pub pv_index: usize, pub pv_start: usize, pub pv_end: usize, + pub cutoff_count: PlyArray, + pub excluded: PlyArray, } impl ThreadData { @@ -191,6 +219,8 @@ impl ThreadData { pv_index: 0, pv_start: 0, pv_end: 0, + cutoff_count: PlyArray::default(), + excluded: PlyArray::default(), } } diff --git a/src/types/moves.rs b/src/types/moves.rs index 07f533aa0..5d66d7f5a 100644 --- a/src/types/moves.rs +++ b/src/types/moves.rs @@ -159,3 +159,9 @@ impl Move { output } } + +impl Default for Move { + fn default() -> Self { + Move::NULL + } +}