feat: uci engine interface
This commit is contained in:
parent
3ebadf995f
commit
5751215ffa
@ -4,6 +4,8 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
|
||||||
|
default-run = "engine"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
133
src/bin/engine.rs
Normal file
133
src/bin/engine.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This file is part of chess_inator.
|
||||||
|
|
||||||
|
chess_inator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
chess_inator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with chess_inator. If not, see https://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! Main UCI engine binary.
|
||||||
|
|
||||||
|
use chess_inator::fen::FromFen;
|
||||||
|
use chess_inator::movegen::{FromUCIAlgebraic, Move, MoveGen, MoveGenType, ToUCIAlgebraic};
|
||||||
|
use chess_inator::Board;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
/// UCI protocol says to ignore any unknown words.
|
||||||
|
///
|
||||||
|
/// This macro exists to avoid copy-pasting this explanation everywhere.
|
||||||
|
macro_rules! ignore {
|
||||||
|
() => {
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// UCI engine metadata query.
|
||||||
|
fn cmd_uci() -> String {
|
||||||
|
let str = "id name chess_inator\n\
|
||||||
|
id author dogeystamp\n\
|
||||||
|
uciok";
|
||||||
|
str.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the `moves` after setting an initial position.
|
||||||
|
fn cmd_position_moves(mut tokens: std::str::SplitWhitespace<'_>, mut board: Board) -> Board {
|
||||||
|
while let Some(token) = tokens.next() {
|
||||||
|
match token {
|
||||||
|
"moves" => {
|
||||||
|
for mv in tokens.by_ref() {
|
||||||
|
let mv = Move::from_uci_algebraic(mv).unwrap();
|
||||||
|
let _ = mv.make(&mut board);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ignore!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the position.
|
||||||
|
fn cmd_position(mut tokens: std::str::SplitWhitespace<'_>) -> Board {
|
||||||
|
while let Some(token) = tokens.next() {
|
||||||
|
match token {
|
||||||
|
"fen" => {
|
||||||
|
let mut fen = String::with_capacity(64);
|
||||||
|
// fen is 6 whitespace-delimited fields
|
||||||
|
for i in 0..6 {
|
||||||
|
fen.push_str(tokens.next().expect("FEN missing fields"));
|
||||||
|
if i < 5 {
|
||||||
|
fen.push(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let board = Board::from_fen(&fen)
|
||||||
|
.unwrap_or_else(|e| panic!("failed to parse fen '{fen}': {e:?}"));
|
||||||
|
let board = cmd_position_moves(tokens, board);
|
||||||
|
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
"startpos" => {
|
||||||
|
let board = Board::starting_pos();
|
||||||
|
let board = cmd_position_moves(tokens, board);
|
||||||
|
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
_ => ignore!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("position command was empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Play the game.
|
||||||
|
fn cmd_go(mut _tokens: std::str::SplitWhitespace<'_>, board: &mut Board) {
|
||||||
|
let mvs: Vec<_> = board.gen_moves(MoveGenType::Legal).into_iter().collect();
|
||||||
|
let chosen = mvs.first();
|
||||||
|
match chosen {
|
||||||
|
Some(mv) => println!("bestmove {}", mv.to_uci_algebraic()),
|
||||||
|
None => println!("bestmove 0000"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
|
||||||
|
let mut board = Board::starting_pos();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut line = String::new();
|
||||||
|
stdin.read_line(&mut line).unwrap();
|
||||||
|
let mut tokens = line.split_whitespace();
|
||||||
|
while let Some(token) = tokens.next() {
|
||||||
|
match token {
|
||||||
|
"uci" => {
|
||||||
|
println!("{}", cmd_uci());
|
||||||
|
}
|
||||||
|
"isready" => {
|
||||||
|
println!("readyok");
|
||||||
|
}
|
||||||
|
"ucinewgame" => {
|
||||||
|
board = Board::starting_pos();
|
||||||
|
}
|
||||||
|
"quit" => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"position" => {
|
||||||
|
board = cmd_position(tokens);
|
||||||
|
}
|
||||||
|
"go" => {
|
||||||
|
cmd_go(tokens, &mut board);
|
||||||
|
}
|
||||||
|
_ => ignore!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -168,7 +168,7 @@ pub struct Move {
|
|||||||
|
|
||||||
impl Move {
|
impl Move {
|
||||||
/// Apply move to a position.
|
/// Apply move to a position.
|
||||||
fn make(self, pos: &mut Board) -> AntiMove {
|
pub fn make(self, pos: &mut Board) -> AntiMove {
|
||||||
let mut anti_move = AntiMove {
|
let mut anti_move = AntiMove {
|
||||||
dest: self.dest,
|
dest: self.dest,
|
||||||
src: self.src,
|
src: self.src,
|
||||||
|
Loading…
Reference in New Issue
Block a user