From 634876822b48a9fabc5dd4ac9b7381c0406f6123 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 8 Jun 2025 16:49:55 -0700 Subject: [PATCH] [explorer] Add a load command Loads a board position from a FEN string. Plumb through setting the Zobrist state on an existing board. Rebuild the hash when setting the state. --- board/src/board.rs | 9 +++++++++ explorer/src/main.rs | 25 ++++++++++++++++++++++++- position/src/position.rs | 14 ++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/board/src/board.rs b/board/src/board.rs index a3afd64..6a93eef 100644 --- a/board/src/board.rs +++ b/board/src/board.rs @@ -306,6 +306,15 @@ impl Board { zobrist.set_hash_value(new_hash); } } + + pub fn zobrist_state(&self) -> Option> { + self.zobrist_hash.as_ref().map(ZobristHash::state) + } + + pub fn set_zobrist_state(&mut self, state: Arc) { + self.zobrist_hash = Some(ZobristHash::new(state)); + self.recompute_zobrist_hash(); + } } impl Board { diff --git a/explorer/src/main.rs b/explorer/src/main.rs index 9be313a..ea8ce26 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -47,6 +47,12 @@ fn command_line() -> Command { .subcommand_help_heading("COMMANDS") .help_template(PARSER_TEMPLATE) .subcommand(Command::new("fen").about("Print the current position as a FEN string")) + .subcommand( + Command::new("load") + .arg(Arg::new("fen").required(true)) + .alias("l") + .about("Load a board position from a FEN string"), + ) .subcommand( Command::new("make") .arg(Arg::new("from").required(true)) @@ -75,7 +81,7 @@ fn command_line() -> Command { .subcommand( Command::new("movement") .arg(Arg::new("square").required(true)) - .about("Show moves of a piece on a square."), + .about("Show moves of a piece on a square"), ) .subcommand( Command::new("reset") @@ -112,6 +118,7 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result { let mut result = CommandResult::default(); match matches.subcommand() { + Some(("load", matches)) => result = do_load_command(state, matches)?, Some(("print", _matches)) => {} Some(("quit", _matches)) => { result.should_continue = false; @@ -184,6 +191,22 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result { Ok(result) } +fn do_load_command(state: &mut State, matches: &clap::ArgMatches) -> anyhow::Result { + let fen_string = matches + .get_one::("fen") + .ok_or(CommandHandlingError::MissingArgument("fen"))?; + + let mut board = Board::from_fen_str(fen_string.as_str())?; + board.set_zobrist_state(state.zobrist.clone()); + + state.position = Position::new(board); + + Ok(CommandResult { + should_continue: true, + should_print_position: true, + }) +} + fn do_reset_command( state: &mut State, matches: &clap::ArgMatches, diff --git a/position/src/position.rs b/position/src/position.rs index 332bf65..f7b7c4a 100644 --- a/position/src/position.rs +++ b/position/src/position.rs @@ -2,6 +2,7 @@ mod captures; +use crate::fen::{FromFenStr, FromFenStrError}; use captures::CapturesList; use chessfriend_bitboard::BitBoard; use chessfriend_board::{ @@ -230,6 +231,10 @@ impl Position { pub fn zobrist_hash(&self) -> Option { self.board.zobrist_hash() } + + pub fn set_zobrist_state(&mut self, state: Arc) { + self.board.set_zobrist_state(state); + } } impl Position { @@ -238,6 +243,15 @@ impl Position { } } +impl FromFenStr for Position { + type Error = FromFenStrError; + + fn from_fen_str(string: &str) -> Result { + let board = Board::from_fen_str(string)?; + Ok(Position::new(board)) + } +} + impl ToFenStr for Position { type Error = ::Error;