engine: cleaning
This commit is contained in:
parent
5d61db1fba
commit
5771930e97
16
src/board.rs
16
src/board.rs
|
@ -69,6 +69,14 @@ pub fn pos(s: &str) -> Pos {
|
||||||
((chars[0] - 0x61) as i8, (chars[1] - 0x31) as i8)
|
((chars[0] - 0x61) as i8, (chars[1] - 0x31) as i8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return string coordinates from Pos.
|
||||||
|
pub fn pos_string(p: &Pos) -> String {
|
||||||
|
let mut bytes = [0u8; 2];
|
||||||
|
bytes[0] = (p.0 + 0x61) as u8;
|
||||||
|
bytes[1] = (p.1 + 0x31) as u8;
|
||||||
|
String::from_utf8_lossy(&bytes).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// Bitboard representation of a chess board.
|
/// Bitboard representation of a chess board.
|
||||||
///
|
///
|
||||||
/// 64 squares, from A1, A2 to H7, H8. A square is an u8, with bits
|
/// 64 squares, from A1, A2 to H7, H8. A square is an u8, with bits
|
||||||
|
@ -229,6 +237,14 @@ mod tests {
|
||||||
assert_eq!(pos("h8"), (7, 7));
|
assert_eq!(pos("h8"), (7, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pos_string() {
|
||||||
|
assert_eq!(pos_string(&(0, 0)), "a1");
|
||||||
|
assert_eq!(pos_string(&(0, 1)), "a2");
|
||||||
|
assert_eq!(pos_string(&(0, 7)), "a8");
|
||||||
|
assert_eq!(pos_string(&(7, 7)), "h8");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_from_fen() {
|
fn test_new_from_fen() {
|
||||||
let b1 = new();
|
let b1 = new();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Vatu engine.
|
//! Vatu engine.
|
||||||
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
use rand::seq::IteratorRandom;
|
use rand::seq::IteratorRandom;
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ pub enum Cmd {
|
||||||
UciGo(Vec<uci::GoArgs>), // UCI "go" command.
|
UciGo(Vec<uci::GoArgs>), // UCI "go" command.
|
||||||
|
|
||||||
// Commands that can be sent by the engine.
|
// Commands that can be sent by the engine.
|
||||||
BestMove(board::Move),
|
BestMove(Option<board::Move>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CASTLING_WH_K: u8 = 0b00000001;
|
pub const CASTLING_WH_K: u8 = 0b00000001;
|
||||||
|
@ -138,15 +140,25 @@ impl Engine {
|
||||||
self.fullmove = fullmove.parse::<i32>().ok().unwrap();
|
self.fullmove = fullmove.parse::<i32>().ok().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_moves(&mut self, moves: &Vec<board::Move>) {
|
||||||
|
moves.iter().for_each(|m| self.apply_move(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_move(&mut self, m: &board::Move) {
|
||||||
|
board::apply_into(&mut self.board, m);
|
||||||
|
}
|
||||||
|
|
||||||
/// Start working on board, returning the best move found.
|
/// Start working on board, returning the best move found.
|
||||||
///
|
///
|
||||||
/// Stop working after `movetime` ms, or go on forever if it's -1.
|
/// Stop working after `movetime` ms, or go on forever if it's -1.
|
||||||
pub fn work(&mut self, _movetime: i32) -> board::Move {
|
pub fn work(&mut self, movetime: i32) -> Option<board::Move> {
|
||||||
// Stupid engine! Return a random move.
|
// Stupid engine! Return a random move.
|
||||||
let moves = rules::get_player_legal_moves(&self.board, self.color);
|
let moves = rules::get_player_legal_moves(&self.board, self.color);
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let best_move = moves.iter().choose(&mut rng).unwrap();
|
let best_move = moves.iter().choose(&mut rng).and_then(|m| Some(*m));
|
||||||
*best_move
|
// board::draw(&self.board);
|
||||||
|
thread::sleep(time::Duration::from_millis(movetime as u64));
|
||||||
|
best_move
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +192,9 @@ impl Engine {
|
||||||
uci::PositionArgs::Startpos => {
|
uci::PositionArgs::Startpos => {
|
||||||
let fen = notation::parse_fen(notation::FEN_START).unwrap();
|
let fen = notation::parse_fen(notation::FEN_START).unwrap();
|
||||||
self.apply_fen(&fen);
|
self.apply_fen(&fen);
|
||||||
|
},
|
||||||
|
uci::PositionArgs::Moves(moves) => {
|
||||||
|
self.apply_moves(&moves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ fn cmd_cli(args: &ArgMatches) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmd_uci(args: &ArgMatches) -> i32 {
|
fn cmd_uci(args: &ArgMatches) -> i32 {
|
||||||
let output = args.value_of("output");
|
let output = args.value_of("log_file");
|
||||||
uci::Uci::start(output);
|
uci::Uci::start(output);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
//! Functions using various notations.
|
//! Functions using various notations.
|
||||||
|
|
||||||
|
use crate::board;
|
||||||
|
|
||||||
|
pub const NULL_MOVE: &str = "0000";
|
||||||
|
|
||||||
|
pub fn move_to_string(m: &board::Move) -> String {
|
||||||
|
let mut move_string = String::new();
|
||||||
|
move_string.push_str(&board::pos_string(&m.0));
|
||||||
|
move_string.push_str(&board::pos_string(&m.1));
|
||||||
|
move_string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_move(m_str: &str) -> board::Move {
|
||||||
|
(board::pos(&m_str[0..2]), board::pos(&m_str[2..4]))
|
||||||
|
}
|
||||||
|
|
||||||
pub const FEN_START: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
pub const FEN_START: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
|
||||||
/// FEN notation for positions, split into fields.
|
/// FEN notation for positions, split into fields.
|
||||||
|
@ -36,6 +51,17 @@ pub fn parse_fen_fields(fields: &[&str]) -> Option<Fen> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_move_to_string() {
|
||||||
|
assert_eq!(move_to_string(&((0, 0), (3, 3))), "a1d4");
|
||||||
|
assert_eq!(move_to_string(&((7, 7), (0, 7))), "h8a8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_move() {
|
||||||
|
assert_eq!(parse_move("a1d4"), ((0, 0), (3, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_fen() {
|
fn test_parse_fen() {
|
||||||
let fen_start = parse_fen(FEN_START).unwrap();
|
let fen_start = parse_fen(FEN_START).unwrap();
|
||||||
|
|
55
src/uci.rs
55
src/uci.rs
|
@ -57,6 +57,7 @@ pub enum UciCmd {
|
||||||
pub enum PositionArgs {
|
pub enum PositionArgs {
|
||||||
Startpos,
|
Startpos,
|
||||||
Fen(notation::Fen),
|
Fen(notation::Fen),
|
||||||
|
Moves(Vec<board::Move>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arguments for the go remote commands.
|
/// Arguments for the go remote commands.
|
||||||
|
@ -112,11 +113,9 @@ impl Uci {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, s: String) {
|
fn log(&mut self, s: String) {
|
||||||
match self.logfile.as_ref() {
|
match &mut self.logfile {
|
||||||
Some(mut f) => {
|
Some(f) => {
|
||||||
f.write_all(s.as_bytes()).unwrap();
|
writeln!(f, "{}", s).unwrap();
|
||||||
f.write_all("\n".as_bytes()).unwrap();
|
|
||||||
f.flush().unwrap();
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
eprintln!("{}", s);
|
eprintln!("{}", s);
|
||||||
|
@ -135,6 +134,7 @@ impl Uci {
|
||||||
pub fn read_stdin(tx: mpsc::Sender<Cmd>) {
|
pub fn read_stdin(tx: mpsc::Sender<Cmd>) {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
loop {
|
loop {
|
||||||
|
s.clear();
|
||||||
match io::stdin().read_line(&mut s) {
|
match io::stdin().read_line(&mut s) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let s = s.trim();
|
let s = s.trim();
|
||||||
|
@ -147,7 +147,6 @@ impl Uci {
|
||||||
eprintln!("Failed to read input: {:?}", e);
|
eprintln!("Failed to read input: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +216,12 @@ impl Uci {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send best move.
|
/// Send best move.
|
||||||
fn send_bestmove(&mut self, m: &board::Move) {
|
fn send_bestmove(&mut self, m: &Option<board::Move>) {
|
||||||
self.send(&format!("bestmove {:?}", m)); // TODO notation conversion
|
let move_str = match m {
|
||||||
|
Some(m) => notation::move_to_string(m),
|
||||||
|
None => notation::NULL_MOVE.to_string(),
|
||||||
|
};
|
||||||
|
self.send(&format!("bestmove {}", move_str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,20 +248,34 @@ fn parse_command(s: &str) -> UciCmd {
|
||||||
|
|
||||||
/// Parse an UCI "position" command.
|
/// Parse an UCI "position" command.
|
||||||
fn parse_position_command(fields: &[&str]) -> UciCmd {
|
fn parse_position_command(fields: &[&str]) -> UciCmd {
|
||||||
// Currently we only match the first subcommand; moves are not supported.
|
let num_fields = fields.len();
|
||||||
|
let mut i = 0;
|
||||||
let mut subcommands = vec!();
|
let mut subcommands = vec!();
|
||||||
match fields[0] {
|
while i < num_fields {
|
||||||
// Subcommand "fen" is followed by a FEN string.
|
match fields[i] {
|
||||||
"fen" => {
|
// Subcommand "fen" is followed by a FEN string.
|
||||||
if let Some(fen) = notation::parse_fen_fields(&fields[1..7]) {
|
"fen" => {
|
||||||
subcommands.push(PositionArgs::Fen(fen))
|
if let Some(fen) = notation::parse_fen_fields(&fields[i + 1 .. i + 7]) {
|
||||||
} else {
|
subcommands.push(PositionArgs::Fen(fen))
|
||||||
return UciCmd::Unknown(format!("Bad format for position fen"))
|
} else {
|
||||||
|
return UciCmd::Unknown(format!("Bad format for position fen"))
|
||||||
|
}
|
||||||
|
i += 6;
|
||||||
}
|
}
|
||||||
|
// Subcommand "startpos" assumes the board is a new game.
|
||||||
|
"startpos" => subcommands.push(PositionArgs::Startpos),
|
||||||
|
// Subcommand "moves" is followed by moves until the end of the command.
|
||||||
|
"moves" => {
|
||||||
|
let mut moves = vec!();
|
||||||
|
while i + 1 < num_fields {
|
||||||
|
moves.push(notation::parse_move(fields[i + 1]));
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
subcommands.push(PositionArgs::Moves(moves));
|
||||||
|
},
|
||||||
|
f => return UciCmd::Unknown(format!("Unknown position subcommand: {}", f)),
|
||||||
}
|
}
|
||||||
// Subcommand "startpos" assumes the board is a new game.
|
i += 1;
|
||||||
"startpos" => subcommands.push(PositionArgs::Startpos),
|
|
||||||
f => return UciCmd::Unknown(format!("Unknown position subcommand: {}", f)),
|
|
||||||
}
|
}
|
||||||
UciCmd::Position(subcommands)
|
UciCmd::Position(subcommands)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue