feat: iterative deepening
This commit is contained in:
parent
69dfa98bef
commit
bec310c182
@ -8,6 +8,7 @@ Features:
|
|||||||
- Piece-square tables
|
- Piece-square tables
|
||||||
- Tapered midgame-endgame evaluation
|
- Tapered midgame-endgame evaluation
|
||||||
- UCI compatibility
|
- UCI compatibility
|
||||||
|
- Iterative deepening
|
||||||
|
|
||||||
## instructions
|
## instructions
|
||||||
|
|
||||||
|
@ -12,12 +12,15 @@ Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
|
|||||||
|
|
||||||
//! Main UCI engine binary.
|
//! Main UCI engine binary.
|
||||||
|
|
||||||
|
use chess_inator::eval::eval_metrics;
|
||||||
use chess_inator::fen::FromFen;
|
use chess_inator::fen::FromFen;
|
||||||
use chess_inator::movegen::{FromUCIAlgebraic, Move, ToUCIAlgebraic};
|
use chess_inator::movegen::{FromUCIAlgebraic, Move, ToUCIAlgebraic};
|
||||||
use chess_inator::search::{best_line, SearchEval};
|
use chess_inator::search::{best_line, InterfaceMsg, SearchEval};
|
||||||
use chess_inator::eval::{eval_metrics};
|
|
||||||
use chess_inator::Board;
|
use chess_inator::Board;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
/// UCI protocol says to ignore any unknown words.
|
/// UCI protocol says to ignore any unknown words.
|
||||||
///
|
///
|
||||||
@ -88,7 +91,18 @@ fn cmd_position(mut tokens: std::str::SplitWhitespace<'_>) -> Board {
|
|||||||
|
|
||||||
/// Play the game.
|
/// Play the game.
|
||||||
fn cmd_go(mut _tokens: std::str::SplitWhitespace<'_>, board: &mut Board) {
|
fn cmd_go(mut _tokens: std::str::SplitWhitespace<'_>, board: &mut Board) {
|
||||||
let (line, eval) = best_line(board, None);
|
// interface-to-engine
|
||||||
|
let (tx1, rx) = channel();
|
||||||
|
let tx2 = tx1.clone();
|
||||||
|
|
||||||
|
// timeout
|
||||||
|
thread::spawn(move || {
|
||||||
|
thread::sleep(Duration::from_millis(1000));
|
||||||
|
let _ = tx2.send(InterfaceMsg::Stop);
|
||||||
|
});
|
||||||
|
|
||||||
|
let (line, eval) = best_line(board, None, Some(rx));
|
||||||
|
|
||||||
let chosen = line.last().copied();
|
let chosen = line.last().copied();
|
||||||
println!(
|
println!(
|
||||||
"info pv{}",
|
"info pv{}",
|
||||||
|
@ -17,6 +17,7 @@ use crate::eval::{Eval, EvalInt};
|
|||||||
use crate::movegen::{Move, MoveGen, ToUCIAlgebraic};
|
use crate::movegen::{Move, MoveGen, ToUCIAlgebraic};
|
||||||
use crate::{Board, Piece};
|
use crate::{Board, Piece};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
// min can't be represented as positive
|
// min can't be represented as positive
|
||||||
const EVAL_WORST: EvalInt = -(EvalInt::MAX);
|
const EVAL_WORST: EvalInt = -(EvalInt::MAX);
|
||||||
@ -103,7 +104,7 @@ impl Default for SearchConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
SearchConfig {
|
SearchConfig {
|
||||||
alpha_beta_on: true,
|
alpha_beta_on: true,
|
||||||
depth: 5,
|
depth: 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,16 +217,54 @@ fn minmax(
|
|||||||
(best_continuation, abs_best)
|
(best_continuation, abs_best)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Messages from the interface to the search thread.
|
||||||
|
pub enum InterfaceMsg {
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterfaceRx = mpsc::Receiver<InterfaceMsg>;
|
||||||
|
|
||||||
|
/// Iteratively deepen search until it is stopped.
|
||||||
|
fn iter_deep(
|
||||||
|
board: &mut Board,
|
||||||
|
config: &SearchConfig,
|
||||||
|
interface: Option<InterfaceRx>,
|
||||||
|
) -> (Vec<Move>, SearchEval) {
|
||||||
|
for depth in 1..=config.depth {
|
||||||
|
let (line, eval) = minmax(board, config, depth, None, None);
|
||||||
|
if let Some(ref rx) = interface {
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(msg) => match msg {
|
||||||
|
InterfaceMsg::Stop => return (line, eval),
|
||||||
|
},
|
||||||
|
Err(e) => match e {
|
||||||
|
mpsc::TryRecvError::Empty => {}
|
||||||
|
mpsc::TryRecvError::Disconnected => panic!("interface thread stopped"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("iterative deepening did not search at all")
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the best line (in reverse order) and its evaluation.
|
/// Find the best line (in reverse order) and its evaluation.
|
||||||
pub fn best_line(board: &mut Board, config: Option<SearchConfig>) -> (Vec<Move>, SearchEval) {
|
pub fn best_line(
|
||||||
|
board: &mut Board,
|
||||||
|
config: Option<SearchConfig>,
|
||||||
|
interface: Option<InterfaceRx>,
|
||||||
|
) -> (Vec<Move>, SearchEval) {
|
||||||
let config = config.unwrap_or_default();
|
let config = config.unwrap_or_default();
|
||||||
let (line, eval) = minmax(board, &config, config.depth, None, None);
|
let (line, eval) = iter_deep(board, &config, interface);
|
||||||
(line, eval)
|
(line, eval)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the best move.
|
/// Find the best move.
|
||||||
pub fn best_move(board: &mut Board, config: Option<SearchConfig>) -> Option<Move> {
|
pub fn best_move(
|
||||||
let (line, _eval) = best_line(board, Some(config.unwrap_or_default()));
|
board: &mut Board,
|
||||||
|
config: Option<SearchConfig>,
|
||||||
|
interface: Option<InterfaceRx>,
|
||||||
|
) -> Option<Move> {
|
||||||
|
let (line, _eval) = best_line(board, Some(config.unwrap_or_default()), interface);
|
||||||
line.last().copied()
|
line.last().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,8 +289,8 @@ mod tests {
|
|||||||
Some(SearchConfig {
|
Some(SearchConfig {
|
||||||
alpha_beta_on: false,
|
alpha_beta_on: false,
|
||||||
depth: 3,
|
depth: 3,
|
||||||
quiesce_depth: Default::default(),
|
|
||||||
}),
|
}),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -262,8 +301,8 @@ mod tests {
|
|||||||
Some(SearchConfig {
|
Some(SearchConfig {
|
||||||
alpha_beta_on: true,
|
alpha_beta_on: true,
|
||||||
depth: 3,
|
depth: 3,
|
||||||
quiesce_depth: Default::default(),
|
|
||||||
}),
|
}),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user