mod config; mod eval; use chess::{Board, ChessMove, MoveGen}; use config::INFO; use eval::eval_board; use itertools::Itertools; use std::collections::HashMap; use std::f64::{INFINITY, NEG_INFINITY}; use std::io::{self, BufRead}; use std::process; use std::str::FromStr; use vampirc_uci::parse_one; use vampirc_uci::{UciMessage, UciOptionConfig, UciTimeControl}; use crate::config::depth; fn main() { let _rng = rand::thread_rng(); let mut board: Option = None; let mut move_history: Vec<(ChessMove, Board)> = vec![]; for line in io::stdin().lock().lines() { let msg: UciMessage = parse_one(&line.unwrap()); match msg { UciMessage::Uci => { println!( "{}\n{}\n{}", UciMessage::Id { name: Some(INFO.to_name()), author: Some(INFO.to_author()) }, UciMessage::Option(UciOptionConfig::Check { name: "EnPassant".to_owned(), default: Some(false) }), UciMessage::UciOk {} ) } UciMessage::IsReady => { println!("{}", UciMessage::ReadyOk) } UciMessage::UciNewGame => { board = Some(Board::default()); move_history = vec![]; } UciMessage::Position { startpos, fen, moves, } => { if startpos { board = Some(Board::default()) } if let Some(fen) = fen { board = Some(Board::from_str(fen.as_str()).expect("Invalid FEN board")) } if !moves.is_empty() { for chess_move in moves.iter() { if let Some(goofy_board) = board { board = Some(goofy_board.make_move_new(*chess_move)); } } } } UciMessage::Go { time_control, search_control, } => { if let Some(tc) = time_control { match tc { UciTimeControl::TimeLeft { white_time: _, black_time: _, white_increment: _, black_increment: _, moves_to_go: _, } => { // FIXME: impl time-related Things } UciTimeControl::Infinite => { // FIXME: impl } UciTimeControl::Ponder => { // FIXME: impl } UciTimeControl::MoveTime(_) => { // FIXME: impl } } } if let Some(_sc) = search_control { // FIXME: impl search control things } if let Some(board) = board { let color = board.side_to_move(); let moves = MoveGen::new_legal(&board); let iter = moves.map(|mov| (mov, board.make_move_new(mov))); let mut moves_hash_map = HashMap::new(); let mut sorted_moves = iter.sorted_by(|a, b| { if !moves_hash_map.contains_key(a) { moves_hash_map.insert( *a, eval_board( a.1, true, depth, move_history.clone(), if move_history.len() > 0 { Some(move_history.last().unwrap().0) } else { None }, color, NEG_INFINITY, INFINITY, ), ); } if !moves_hash_map.contains_key(b) { moves_hash_map.insert( *b, eval_board( b.1, true, depth, move_history.clone(), None, color, NEG_INFINITY, INFINITY, ), ); } let a_eval = moves_hash_map.get(a).unwrap(); let b_eval = moves_hash_map.get(b).unwrap(); b_eval.total_cmp(a_eval) }); let best_move = sorted_moves.next().unwrap(); let worst_move = sorted_moves.last().unwrap_or(best_move); move_history.push(best_move); eprintln!( "best move: {}, {}", best_move.0, moves_hash_map.get(&best_move).unwrap_or(&0.0) ); eprintln!( "worst move: {}, {}", worst_move.0, moves_hash_map.get(&worst_move).unwrap_or(&0.0) ); println!("bestmove {}", best_move.0); } } UciMessage::Stop => { // FIXME: impl } UciMessage::Quit => { process::exit(0); } _ => { todo!("{}", msg.to_string()) } } } }