implement go
This commit is contained in:
		
							parent
							
								
									a46ff43db4
								
							
						
					
					
						commit
						d68d7023e1
					
				@ -6,10 +6,13 @@ pub mod uci_command;
 | 
			
		||||
use log::{info, warn};
 | 
			
		||||
use std::io::*;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use std::result::Result;
 | 
			
		||||
use crate::uci_command::*;
 | 
			
		||||
 | 
			
		||||
use chess::{Game, Board, ChessMove};
 | 
			
		||||
 | 
			
		||||
const DEFAULT_TIME: (Option<Duration>, Option<Duration>) = (Some(Duration::from_secs(120 * 60)), None);
 | 
			
		||||
 | 
			
		||||
/// Structure used to manage a chess game with a uci engine.
 | 
			
		||||
///
 | 
			
		||||
/// It needs a in / out communication channel to read / push line by line uci commands
 | 
			
		||||
@ -40,9 +43,9 @@ pub struct UciEngine<Fi: Read, Fo: Write> {
 | 
			
		||||
    initial: Board,
 | 
			
		||||
    game: Game,
 | 
			
		||||
    /// white (total, incr), black (total, incr)
 | 
			
		||||
    time: ((Option<Duration>, Option<Duration>), (Option<Duration>, Option<Duration>)),
 | 
			
		||||
    time: [(Option<Duration>, Option<Duration>); 2],
 | 
			
		||||
    /// white, black
 | 
			
		||||
    player: (Player, Player)
 | 
			
		||||
    player: [Player; 2],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum UciOption {
 | 
			
		||||
@ -74,26 +77,26 @@ impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
            uciok: false,
 | 
			
		||||
            initial: Board::default(),
 | 
			
		||||
            game: Game::new(),
 | 
			
		||||
            time: ((None, None), (None, None)),
 | 
			
		||||
            player: (Player::Human{elo: None}, Player::Human{elo: None}),
 | 
			
		||||
            time: [DEFAULT_TIME; 2],
 | 
			
		||||
            player: [Player::Human{elo: None}; 2],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn game_option(&mut self, option: GameOption) -> GameOption {
 | 
			
		||||
        let old_value: GameOption;
 | 
			
		||||
        match option {
 | 
			
		||||
            GameOption::WhiteTotalTime{value} => {old_value = GameOption::WhiteTotalTime { value: self.time.0.0 };
 | 
			
		||||
                                                  self.time.0.0 = value},
 | 
			
		||||
            GameOption::BlackTotalTime{value} => {old_value = GameOption::BlackTotalTime { value: self.time.1.0 };
 | 
			
		||||
                                                  self.time.1.0 = value},
 | 
			
		||||
            GameOption::WhiteIncrement{value} => {old_value = GameOption::WhiteIncrement { value: self.time.0.1 };
 | 
			
		||||
                                                  self.time.0.1 = value},
 | 
			
		||||
            GameOption::BlackIncrement{value} => {old_value = GameOption::BlackIncrement { value: self.time.1.1 };
 | 
			
		||||
                                                  self.time.1.1 = value},
 | 
			
		||||
            GameOption::WhitePlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player.0 };
 | 
			
		||||
                                               self.player.0 = value},
 | 
			
		||||
            GameOption::BlackPlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player.1 };
 | 
			
		||||
                                               self.player.1 = value},
 | 
			
		||||
            GameOption::WhiteTotalTime{value} => {old_value = GameOption::WhiteTotalTime { value: self.time[Color::White.to_index()].0 };
 | 
			
		||||
                                                  self.time[Color::White.to_index()].0 = value},
 | 
			
		||||
            GameOption::BlackTotalTime{value} => {old_value = GameOption::BlackTotalTime { value: self.time[Color::Black.to_index()].0 };
 | 
			
		||||
                                                  self.time[Color::Black.to_index()].0 = value},
 | 
			
		||||
            GameOption::WhiteIncrement{value} => {old_value = GameOption::WhiteIncrement { value: self.time[Color::White.to_index()].1 };
 | 
			
		||||
                                                  self.time[Color::White.to_index()].1 = value},
 | 
			
		||||
            GameOption::BlackIncrement{value} => {old_value = GameOption::BlackIncrement { value: self.time[Color::Black.to_index()].1 };
 | 
			
		||||
                                                  self.time[Color::Black.to_index()].1 = value},
 | 
			
		||||
            GameOption::WhitePlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player[Color::White.to_index()] };
 | 
			
		||||
                                               self.player[Color::White.to_index()] = value},
 | 
			
		||||
            GameOption::BlackPlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player[Color::Black.to_index()] };
 | 
			
		||||
                                               self.player[Color::Black.to_index()] = value},
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        old_value
 | 
			
		||||
@ -172,20 +175,11 @@ impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
        self.id.update_from_str(name, author);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn uciok(&mut self){
 | 
			
		||||
        self.uciok = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Tell whether the uci engine has initialized
 | 
			
		||||
    pub fn is_uciok(&self) -> bool {
 | 
			
		||||
        self.uciok
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Execute a uci command
 | 
			
		||||
    ///
 | 
			
		||||
    /// if `EngineCommand::Id`: update name or authorship of the engine
 | 
			
		||||
    /// if `EngineCommand::UciOk`: end engine initialization phase
 | 
			
		||||
    pub fn exec(&mut self, command: &str) -> std::result::Result<EngineCommand, &'static str> {
 | 
			
		||||
    pub fn exec(&mut self, command: &str) -> Result<EngineCommand, &'static str> {
 | 
			
		||||
        let uci_command = parse (&mut command.to_string());
 | 
			
		||||
        match  uci_command.clone() {
 | 
			
		||||
            Ok(EngineCommand::Id{id}) => self.update(&id),
 | 
			
		||||
@ -259,6 +253,52 @@ impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
    fn uciok(&mut self){
 | 
			
		||||
        self.uciok = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Tell whether the uci engine has initialized
 | 
			
		||||
    pub fn is_uciok(&self) -> bool {
 | 
			
		||||
        self.uciok
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn human_play(&mut self, chess_move: ChessMove) -> Result<ChessMove, &'static str> {
 | 
			
		||||
        match self.player[self.side_to_move().to_index()] {
 | 
			
		||||
            Player::Human{..} => {
 | 
			
		||||
                if self.make_move(chess_move) {
 | 
			
		||||
                    Ok(chess_move)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err("Invalid move for human player")
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            Player::Machine {..} => Err("Not a human to play for current color.")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn go(&mut self) -> Result<(), &'static str> {
 | 
			
		||||
        match self.player[self.side_to_move().to_index()] {
 | 
			
		||||
            Player::Human{..} => Err("Not a machine to play for current color."),
 | 
			
		||||
            Player::Machine {elo} => 
 | 
			
		||||
            {
 | 
			
		||||
                if self.is_uciok() {
 | 
			
		||||
                    if let Some(elo) = elo {
 | 
			
		||||
                        self.push(GuiCommand::SetOption {option: Opt::UCILimitStrength{value: true}});
 | 
			
		||||
                        self.push(GuiCommand::SetOption {option: Opt::UCIElo{value: elo}});
 | 
			
		||||
                    }
 | 
			
		||||
                    let (wtime, wincr) = self.time[Color::White.to_index()];
 | 
			
		||||
                    let (btime, bincr) = self.time[Color::Black.to_index()];
 | 
			
		||||
                    self.push(GuiCommand::Go{wtime, wincr, btime, bincr});
 | 
			
		||||
 | 
			
		||||
                    Ok(())
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err("UCI engine not ready")                    
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
use chess::{Square, Piece, Color};
 | 
			
		||||
impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
    pub fn piece_on(&self, square: Square) -> Option<Piece> {
 | 
			
		||||
@ -271,5 +311,9 @@ impl<Fi: Read, Fo:  Write> UciEngine<Fi, Fo> {
 | 
			
		||||
    pub fn current_position(&self) -> Board {
 | 
			
		||||
        self.game.current_position()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn side_to_move(&self) -> Color {
 | 
			
		||||
        self.game.side_to_move()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
//  LocalWords:  uci
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,10 @@ impl Id {
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct Info {}
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct Opt{}
 | 
			
		||||
pub enum Opt{
 | 
			
		||||
    UCILimitStrength{value: bool},
 | 
			
		||||
    UCIElo{value: u32},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum EngineCommand {
 | 
			
		||||
@ -58,7 +61,8 @@ pub enum GuiCommand {
 | 
			
		||||
    Register, // unimplemented
 | 
			
		||||
    UciNewGame,
 | 
			
		||||
    Position{position: Option<Board>, moves: Vec<Action>},
 | 
			
		||||
    Go,
 | 
			
		||||
    Go{wtime: Option<Duration>, wincr: Option<Duration>,
 | 
			
		||||
       btime: Option<Duration>, bincr: Option<Duration>},
 | 
			
		||||
    SearchMoves{moves: Vec<ChessMove>},
 | 
			
		||||
    Ponder,
 | 
			
		||||
    WTime{time: Duration},
 | 
			
		||||
@ -117,6 +121,20 @@ impl fmt::Display for GuiCommand {
 | 
			
		||||
                                      {chessmove.to_string()} else {"".to_string()}), "")
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            GuiCommand::SetOption { option } => {
 | 
			
		||||
                match option {
 | 
			
		||||
                    Opt::UCILimitStrength { value } => write!(f, "setoption name UCI_LimitStrength value {value}"),
 | 
			
		||||
                    Opt::UCIElo { value } => write!(f,"setoption name UCI_Elo value {value}"),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            GuiCommand::Go { wtime, wincr, btime, bincr } => {    
 | 
			
		||||
                let wtime = if let Some(wtime) = wtime {format!(" wtime {}", wtime.as_millis())} else {"".to_string()};
 | 
			
		||||
                let btime = if let Some(btime) = btime {format!(" btime {}", btime.as_millis())} else {"".to_string()};
 | 
			
		||||
                let wincr = if let Some(wincr) = wincr {format!(" wincr {}", wincr.as_millis())} else {"".to_string()};
 | 
			
		||||
                let bincr = if let Some(bincr) = bincr {format!(" bincr {}", bincr.as_millis())} else {"".to_string()};
 | 
			
		||||
                write!(f, "go{}{}{}{}", wtime, btime, wincr, bincr)
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            a => unimplemented!("{:?}", a),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user