feat: stand-pat on quiescence search
gotta remember that not capturing is an option too
This commit is contained in:
parent
54a4cd07ac
commit
0120c95097
11
src/eval.rs
11
src/eval.rs
@ -509,16 +509,17 @@ mod tests {
|
||||
// expected (signed) value gain of exchange
|
||||
Rook.value(),
|
||||
),
|
||||
(
|
||||
"8/8/4b3/2kq4/2PKP3/8/8/8 w - - 0 1",
|
||||
"d5",
|
||||
Queen.value(),
|
||||
),
|
||||
("8/8/4b3/2kq4/2PKP3/8/8/8 w - - 0 1", "d5", Queen.value()),
|
||||
(
|
||||
"r3k2r/1pq2pbp/6p1/p2Qpb2/1N6/2P3P1/PB2PPBP/R3K2R w KQkq - 0 14",
|
||||
"e5",
|
||||
0,
|
||||
),
|
||||
(
|
||||
"r3k2r/1pq2pbp/6p1/p3p3/P5b1/2P3P1/1BN1PPBP/R2QK2R b KQkq - 0 14",
|
||||
"e2",
|
||||
0,
|
||||
),
|
||||
];
|
||||
|
||||
for (fen, dest, expected) in test_cases {
|
||||
|
@ -1667,25 +1667,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_capture_movegen() {
|
||||
let test_cases = [(
|
||||
// fen
|
||||
"8/3q4/5N2/8/8/8/8/3K4 w - - 0 1",
|
||||
// expected moves generated
|
||||
"f6d7",
|
||||
),
|
||||
(
|
||||
"8/8/8/3pP3/2K5/8/8/8 w - d6 0 1",
|
||||
// holy hell
|
||||
"e5d6 c4d5",
|
||||
),
|
||||
(
|
||||
"8/2q5/3K4/8/8/8/8/8 w - - 0 1",
|
||||
"d6c7",
|
||||
),
|
||||
(
|
||||
"2Q5/3r2R1/2B1PN2/8/3K4/8/8/8 w - - 0 1",
|
||||
"c6d7 e6d7 c8d7 f6d7 g7d7",
|
||||
),
|
||||
let test_cases = [
|
||||
(
|
||||
// fen
|
||||
"8/3q4/5N2/8/8/8/8/3K4 w - - 0 1",
|
||||
// expected moves generated
|
||||
"f6d7",
|
||||
),
|
||||
(
|
||||
"8/8/8/3pP3/2K5/8/8/8 w - d6 0 1",
|
||||
// holy hell
|
||||
"e5d6 c4d5",
|
||||
),
|
||||
("8/2q5/3K4/8/8/8/8/8 w - - 0 1", "d6c7"),
|
||||
(
|
||||
"2Q5/3r2R1/2B1PN2/8/3K4/8/8/8 w - - 0 1",
|
||||
"c6d7 e6d7 c8d7 f6d7 g7d7",
|
||||
),
|
||||
];
|
||||
|
||||
for (fen, expected) in test_cases {
|
||||
|
@ -23,5 +23,5 @@ pub use crate::search::{
|
||||
best_line, best_move, EngineState, SearchConfig, SearchEval, TimeLimits, TranspositionTable,
|
||||
};
|
||||
pub use crate::{
|
||||
Board, ColPiece, Color, Piece, BOARD_HEIGHT, BOARD_WIDTH, N_COLORS, N_PIECES, N_SQUARES, Square,
|
||||
Board, ColPiece, Color, Piece, Square, BOARD_HEIGHT, BOARD_WIDTH, N_COLORS, N_PIECES, N_SQUARES,
|
||||
};
|
||||
|
@ -122,9 +122,8 @@ impl Default for SearchConfig {
|
||||
fn default() -> Self {
|
||||
SearchConfig {
|
||||
alpha_beta_on: true,
|
||||
// try to make this even to be more conservative and avoid horizon problem
|
||||
depth: 10,
|
||||
qdepth: 2,
|
||||
qdepth: 4,
|
||||
enable_trans_table: true,
|
||||
transposition_size: 24,
|
||||
}
|
||||
@ -209,13 +208,20 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
||||
}
|
||||
}
|
||||
|
||||
// quiescence stand-pat score (only calculated if needed).
|
||||
// this is where static eval goes.
|
||||
let mut board_eval: Option<EvalInt> = None;
|
||||
|
||||
if mm.quiesce {
|
||||
board_eval = Some(board.eval() * EvalInt::from(board.turn.sign()));
|
||||
}
|
||||
|
||||
if mm.depth == 0 {
|
||||
if mm.quiesce || board.recap_sq.is_none() {
|
||||
// if we're done with quiescence, static eval.
|
||||
// if there is no capture, skip straight to static eval.
|
||||
let eval = board.eval() * EvalInt::from(board.turn.sign());
|
||||
return (Vec::new(), SearchEval::Exact(eval));
|
||||
if mm.quiesce {
|
||||
// we hit the limit on quiescence depth
|
||||
return (Vec::new(), SearchEval::Exact(board_eval.unwrap()));
|
||||
} else {
|
||||
// enter quiescence search
|
||||
return minmax(
|
||||
board,
|
||||
state,
|
||||
@ -261,11 +267,15 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
||||
mvs.sort_unstable_by_key(|mv| -mv.0);
|
||||
|
||||
let mut abs_best = SearchEval::Exact(EVAL_WORST);
|
||||
|
||||
if mm.quiesce {
|
||||
// stand pat
|
||||
abs_best = SearchEval::Exact(board_eval.unwrap());
|
||||
}
|
||||
|
||||
let mut best_move: Option<Move> = None;
|
||||
let mut best_continuation: Vec<Move> = Vec::new();
|
||||
|
||||
let n_non_qmoves = mvs.len();
|
||||
|
||||
// determine moves that are allowed in quiescence
|
||||
if mm.quiesce {
|
||||
// use static exchange evaluation to prune moves
|
||||
@ -276,7 +286,11 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
||||
});
|
||||
}
|
||||
|
||||
if n_non_qmoves == 0 {
|
||||
if mvs.is_empty() {
|
||||
if mm.quiesce {
|
||||
// use stand pat
|
||||
return (Vec::new(), SearchEval::Exact(board_eval.unwrap()));
|
||||
}
|
||||
let is_in_check = board.is_check(board.turn);
|
||||
|
||||
if is_in_check {
|
||||
@ -285,10 +299,6 @@ fn minmax(board: &mut Board, state: &mut EngineState, mm: MinmaxState) -> (Vec<M
|
||||
// stalemate
|
||||
return (Vec::new(), SearchEval::Exact(0));
|
||||
}
|
||||
} else if mvs.is_empty() {
|
||||
// pruned all the moves due to quiescence
|
||||
let eval = board.eval() * EvalInt::from(board.turn.sign());
|
||||
return (Vec::new(), SearchEval::Exact(eval));
|
||||
}
|
||||
|
||||
for (_priority, mv) in mvs {
|
||||
|
Loading…
Reference in New Issue
Block a user