feat: uci options, quiet position detector
This commit is contained in:
parent
fc8eab4d4b
commit
ede46552fe
@ -165,6 +165,8 @@ pub struct MsgBestmove {
|
||||
pub pv: Vec<Move>,
|
||||
/// Evaluation of the position
|
||||
pub eval: SearchEval,
|
||||
/// Extra information (displayed as `info string`).
|
||||
pub info: Vec<String>,
|
||||
}
|
||||
|
||||
/// Interface messages that may be received by main's channel.
|
||||
|
72
src/main.rs
72
src/main.rs
@ -51,8 +51,9 @@ macro_rules! ignore {
|
||||
/// UCI engine metadata query.
|
||||
fn cmd_uci() -> String {
|
||||
let str = "id name chess_inator\n\
|
||||
id author dogeystamp\n\
|
||||
uciok";
|
||||
id author dogeystamp\n\
|
||||
option name NNUETrainInfo type check default false\n\
|
||||
uciok";
|
||||
str.into()
|
||||
}
|
||||
|
||||
@ -123,7 +124,6 @@ fn cmd_go(mut tokens: std::str::SplitWhitespace<'_>, state: &mut MainState) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
while let Some(token) = tokens.next() {
|
||||
match token {
|
||||
"wtime" => {
|
||||
@ -207,6 +207,50 @@ fn cmd_eval(mut _tokens: std::str::SplitWhitespace<'_>, state: &mut MainState) {
|
||||
println!("- total: {}", res.total_eval);
|
||||
}
|
||||
|
||||
fn match_true_false(s: &str) -> Option<bool> {
|
||||
match s {
|
||||
"true" => Some(true),
|
||||
"false" => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set engine options via UCI.
|
||||
fn cmd_setoption(mut tokens: std::str::SplitWhitespace<'_>, state: &mut MainState) {
|
||||
while let Some(token) = tokens.next() {
|
||||
fn get_val(mut tokens: std::str::SplitWhitespace<'_>) -> Option<String> {
|
||||
if let Some("value") = tokens.next() {
|
||||
if let Some(value) = tokens.next() {
|
||||
return Some(value.to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
match token {
|
||||
"name" => {
|
||||
if let Some(name) = tokens.next() {
|
||||
match name {
|
||||
"NNUETrainInfo" => {
|
||||
if let Some(value) = get_val(tokens) {
|
||||
if let Some(value) = match_true_false(&value) {
|
||||
state.config.nnue_train_info = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("info string Unknown option: {}", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ignore!(),
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Root UCI parser.
|
||||
fn cmd_root(mut tokens: std::str::SplitWhitespace<'_>, state: &mut MainState) {
|
||||
while let Some(token) = tokens.next() {
|
||||
@ -242,6 +286,9 @@ fn cmd_root(mut tokens: std::str::SplitWhitespace<'_>, state: &mut MainState) {
|
||||
state.tx_engine.send(MsgToEngine::Stop).unwrap();
|
||||
}
|
||||
}
|
||||
"setoption" => {
|
||||
cmd_setoption(tokens, state);
|
||||
}
|
||||
// non-standard command.
|
||||
"eval" => {
|
||||
cmd_eval(tokens, state);
|
||||
@ -274,6 +321,10 @@ fn outp_bestmove(bestmove: MsgBestmove) {
|
||||
panic!("info string ERROR: stopped search")
|
||||
}
|
||||
}
|
||||
for line in bestmove.info {
|
||||
println!("info string {line}");
|
||||
}
|
||||
|
||||
match chosen {
|
||||
Some(mv) => println!("bestmove {}", mv.to_uci_algebraic()),
|
||||
None => println!("bestmove 0000"),
|
||||
@ -315,8 +366,21 @@ fn task_engine(tx_main: Sender<MsgToMain>, rx_engine: Receiver<MsgToEngine>) {
|
||||
state.config = msg_box.config;
|
||||
state.time_lims = msg_box.time_lims;
|
||||
let (pv, eval) = best_line(&mut board, &mut state);
|
||||
|
||||
let mut info: Vec<String> = Vec::new();
|
||||
if state.config.nnue_train_info {
|
||||
let is_quiet = chess_inator::search::is_quiescent_position(&board, eval);
|
||||
|
||||
let is_quiet = if is_quiet {"quiet"} else {"non-quiet"};
|
||||
info.push(format!("NNUETrainInfo {}", is_quiet))
|
||||
}
|
||||
|
||||
tx_main
|
||||
.send(MsgToMain::Bestmove(MsgBestmove { pv, eval }))
|
||||
.send(MsgToMain::Bestmove(MsgBestmove {
|
||||
pv,
|
||||
eval,
|
||||
info,
|
||||
}))
|
||||
.unwrap();
|
||||
}
|
||||
MsgToEngine::Stop => {}
|
||||
|
@ -128,6 +128,8 @@ pub struct SearchConfig {
|
||||
pub enable_trans_table: bool,
|
||||
/// Transposition table size (2^n where this is n)
|
||||
pub transposition_size: usize,
|
||||
/// Print machine-readable information about the position during NNUE training data generation.
|
||||
pub nnue_train_info: bool,
|
||||
}
|
||||
|
||||
impl Default for SearchConfig {
|
||||
@ -139,6 +141,7 @@ impl Default for SearchConfig {
|
||||
contempt: 0,
|
||||
enable_trans_table: true,
|
||||
transposition_size: 24,
|
||||
nnue_train_info: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -450,11 +453,7 @@ impl TimeLimits {
|
||||
/// Make time limits based on wtime, btime (but color-independent).
|
||||
///
|
||||
/// Also takes in eval metrics, for instance to avoid wasting too much time in the opening.
|
||||
pub fn from_ourtime_theirtime(
|
||||
ourtime_ms: u64,
|
||||
_theirtime_ms: u64,
|
||||
eval: EvalMetrics,
|
||||
) -> Self {
|
||||
pub fn from_ourtime_theirtime(ourtime_ms: u64, _theirtime_ms: u64, eval: EvalMetrics) -> Self {
|
||||
// hard timeout (max)
|
||||
let mut hard_ms = 100_000;
|
||||
// soft timeout (default max)
|
||||
@ -550,3 +549,27 @@ pub fn best_move(board: &mut Board, engine_state: &mut EngineState) -> Option<Mo
|
||||
let (line, _eval) = best_line(board, engine_state);
|
||||
line.last().copied()
|
||||
}
|
||||
|
||||
/// Utility for NNUE training set generation to determine if a position is quiet or not.
|
||||
///
|
||||
/// Our definition of "quiet" is that there are no checks, and the static and quiescence search
|
||||
/// evaluations are similar. (See https://arxiv.org/html/2412.17948v1.)
|
||||
///
|
||||
/// It is the caller's responsibility to get the search evaluation and pass it to this function.
|
||||
pub fn is_quiescent_position(board: &Board, eval: SearchEval) -> bool {
|
||||
// max centipawn value difference to call "similar"
|
||||
const THRESHOLD: EvalInt = 170;
|
||||
|
||||
if board.is_check(board.turn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if matches!(eval, SearchEval::Checkmate(_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// white perspective
|
||||
let abs_eval = EvalInt::from(eval) * EvalInt::from(board.turn.sign());
|
||||
|
||||
(board.eval() - EvalInt::from(abs_eval)).abs() <= THRESHOLD.abs()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user