use crate::search::{
history::{
ContinuationHistory, PawnHistory, CONTINUATION_HISTORY_WEIGHTS, TT_MOVE_HISTORY_BONUS,
TT_MOVE_HISTORY_MALUS,
},
tt_history::TTMoveHistory,
ContHistKey, LimitsType, Search, SearchInfo, Stack,
};
use crate::types::{Move, Piece, Square};
const STACK_SIZE: usize = 64 * 1024 * 1024;
#[test]
fn tt_move_history_updates_on_bestmove() {
std::thread::Builder::new()
.stack_size(STACK_SIZE)
.spawn(|| {
let mut search = Search::new(16);
let mut pos = crate::position::Position::new();
pos.set_hirate();
let limits = LimitsType {
depth: 1,
..Default::default()
};
let _ = search.go(&mut pos, limits, None::<fn(&SearchInfo)>);
let opts = search.time_options(); assert!(opts.minimum_thinking_time > 0);
})
.unwrap()
.join()
.unwrap();
}
#[test]
fn continuation_history_updates_on_quiet_best() {
std::thread::Builder::new()
.stack_size(STACK_SIZE)
.spawn(|| {
let mut search = Search::new(16);
let mut pos = crate::position::Position::new();
pos.set_hirate();
let mv1 = Move::from_usi("7g7f").unwrap();
let mv2 = Move::from_usi("3c3d").unwrap();
let gives_check1 = pos.gives_check(mv1);
pos.do_move(mv1, gives_check1);
let gives_check2 = pos.gives_check(mv2);
pos.do_move(mv2, gives_check2);
let limits = LimitsType {
depth: 2,
..Default::default()
};
let result = search.go(&mut pos, limits, None::<fn(&SearchInfo)>);
assert!(result.best_move.is_some(), "探索結果が存在するべき");
})
.unwrap()
.join()
.unwrap();
}
#[test]
fn tt_move_history_positive_update() {
let mut history = TTMoveHistory::new();
let ply = 5;
assert_eq!(history.get(ply), 0);
history.update(ply, TT_MOVE_HISTORY_BONUS);
let value = history.get(ply);
assert!(
value > 0,
"TTMoveHistory should be positive after +{TT_MOVE_HISTORY_BONUS} bonus, got {value}"
);
}
#[test]
fn tt_move_history_negative_update() {
let mut history = TTMoveHistory::new();
let ply = 5;
for _ in 0..5 {
history.update(ply, TT_MOVE_HISTORY_BONUS);
}
let before = history.get(ply);
assert!(before > 0, "History should be positive before malus");
history.update(ply, TT_MOVE_HISTORY_MALUS);
let after = history.get(ply);
assert!(
after < before,
"TTMoveHistory should decrease after {TT_MOVE_HISTORY_MALUS} malus"
);
}
#[test]
fn tt_move_history_constants_are_correct() {
assert_eq!(TT_MOVE_HISTORY_BONUS, 811);
assert_eq!(TT_MOVE_HISTORY_MALUS, -848);
}
#[test]
fn continuation_history_basic_update() {
let mut cont_hist = ContinuationHistory::new_boxed();
let prev_pc = Piece::B_PAWN;
let prev_to = unsafe { Square::from_u8_unchecked(60) }; let pc = Piece::B_PAWN;
let to = unsafe { Square::from_u8_unchecked(51) };
assert_eq!(cont_hist.get(prev_pc, prev_to, pc, to), 0);
cont_hist.update(prev_pc, prev_to, pc, to, 100);
let value = cont_hist.get(prev_pc, prev_to, pc, to);
assert!(value > 0, "ContinuationHistory should increase after update");
}
#[test]
fn continuation_history_weights_are_correct() {
assert_eq!(CONTINUATION_HISTORY_WEIGHTS.len(), 6);
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[0], (1, 1108));
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[1], (2, 652));
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[2], (3, 273));
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[3], (4, 572));
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[4], (5, 126));
assert_eq!(CONTINUATION_HISTORY_WEIGHTS[5], (6, 449));
}
#[test]
fn continuation_history_weighted_updates() {
let mut cont_hist = ContinuationHistory::new_boxed();
let base_bonus = 1000;
let pc = Piece::B_PAWN;
let to = unsafe { Square::from_u8_unchecked(60) };
for (ply_back, weight) in CONTINUATION_HISTORY_WEIGHTS.iter() {
let prev_pc = Piece::B_PAWN;
let prev_to = unsafe { Square::from_u8_unchecked((*ply_back % 81) as u8) };
let near_ply_offset = if *ply_back < 2 { 80 } else { 0 };
let adjusted_bonus = base_bonus * weight / 1024 + near_ply_offset;
cont_hist.update(prev_pc, prev_to, pc, to, adjusted_bonus);
}
let sq_1 = unsafe { Square::from_u8_unchecked(1) };
let sq_5 = unsafe { Square::from_u8_unchecked(5) };
let value_1_ply = cont_hist.get(Piece::B_PAWN, sq_1, pc, to);
let value_5_ply = cont_hist.get(Piece::B_PAWN, sq_5, pc, to);
assert!(
value_1_ply > value_5_ply,
"1 ply back (weight=1108) should have higher value than 5 ply back (weight=126)"
);
}
#[test]
fn cont_hist_key_construction() {
let key = ContHistKey::new(true, false, Piece::B_GOLD, Square::SQ_55);
assert!(key.in_check);
assert!(!key.capture);
assert_eq!(key.piece, Piece::B_GOLD);
assert_eq!(key.to, Square::SQ_55);
}
#[test]
fn stack_cont_hist_key_option() {
let mut stack = Stack::default();
assert!(stack.cont_hist_key.is_none());
let sq = unsafe { Square::from_u8_unchecked(22) };
stack.cont_hist_key = Some(ContHistKey::new(false, true, Piece::W_SILVER, sq));
let key = stack.cont_hist_key.unwrap();
assert!(!key.in_check);
assert!(key.capture);
assert_eq!(key.piece, Piece::W_SILVER);
assert_eq!(key.to, sq);
}
#[test]
fn pawn_history_basic_update() {
let mut history = PawnHistory::new_boxed();
let pawn_idx = 42; let pc = Piece::B_PAWN;
let to = unsafe { Square::from_u8_unchecked(60) };
assert_eq!(history.get(pawn_idx, pc, to), 0);
history.update(pawn_idx, pc, to, 200);
let value = history.get(pawn_idx, pc, to);
assert!(value > 0, "PawnHistory should increase after update");
}