[explorer] Add several commands to help with debugging
flags : Print flags for the current board position. This prints the castling rights and whether the player can castle (regardless of whether they have the right). make : Finally reimplement the make command. Change the format so it takes a move in the UCI long algebraic style. perft : Run perft to a given depth on the current board position.
This commit is contained in:
		
							parent
							
								
									6996cbeb15
								
							
						
					
					
						commit
						bf17017694
					
				
					 1 changed files with 92 additions and 9 deletions
				
			
		|  | @ -1,12 +1,14 @@ | |||
| // Eryn Wells <eryn@erynwells.me>
 | ||||
| 
 | ||||
| use chessfriend_board::ZobristState; | ||||
| use chessfriend_board::castle::CastleEvaluationError; | ||||
| use chessfriend_board::{Board, fen::FromFenStr}; | ||||
| use chessfriend_board::{CastleParameters, ZobristState}; | ||||
| use chessfriend_core::random::RandomNumberGenerator; | ||||
| use chessfriend_core::{Color, Piece, Shape, Square}; | ||||
| use chessfriend_moves::GeneratedMove; | ||||
| use chessfriend_core::{Color, Piece, Shape, Square, Wing}; | ||||
| use chessfriend_moves::algebraic::AlgebraicMoveComponents; | ||||
| use chessfriend_moves::{GeneratedMove, ValidateMove}; | ||||
| use chessfriend_position::{PlacePieceStrategy, Position, fen::ToFenStr}; | ||||
| use clap::{Arg, Command}; | ||||
| use clap::{Arg, Command, value_parser}; | ||||
| use rustyline::DefaultEditor; | ||||
| use rustyline::error::ReadlineError; | ||||
| use std::sync::Arc; | ||||
|  | @ -45,6 +47,7 @@ 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("flags").about("Print flags for the current position")) | ||||
|         .subcommand( | ||||
|             Command::new("load") | ||||
|                 .arg(Arg::new("fen").required(true)) | ||||
|  | @ -53,8 +56,7 @@ fn command_line() -> Command { | |||
|         ) | ||||
|         .subcommand( | ||||
|             Command::new("make") | ||||
|                 .arg(Arg::new("from").required(true)) | ||||
|                 .arg(Arg::new("to").required(true)) | ||||
|                 .arg(Arg::new("move").required(true)) | ||||
|                 .alias("m") | ||||
|                 .about("Make a move"), | ||||
|         ) | ||||
|  | @ -81,6 +83,14 @@ fn command_line() -> Command { | |||
|                 .arg(Arg::new("square").required(true)) | ||||
|                 .about("Show moves of a piece on a square"), | ||||
|         ) | ||||
|         .subcommand( | ||||
|             Command::new("perft") | ||||
|                 .arg(Arg::new("depth") | ||||
|                     .required(true) | ||||
|                     .value_parser(value_parser!(usize)) | ||||
|                 ) | ||||
|                 .about("Run Perft on the current position to the given depth") | ||||
|         ) | ||||
|         .subcommand( | ||||
|             Command::new("reset") | ||||
|                 .subcommand(Command::new("clear").about("Reset to a cleared board")) | ||||
|  | @ -107,6 +117,12 @@ enum CommandHandlingError<'a> { | |||
| 
 | ||||
|     #[error("no piece on {0}")] | ||||
|     NoPiece(Square), | ||||
| 
 | ||||
|     #[error("{value:?} is not a valid value for {argument_name:?}")] | ||||
|     ValueError { | ||||
|         argument_name: &'static str, | ||||
|         value: String, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| fn respond(line: &str, state: &mut State) -> anyhow::Result<CommandResult> { | ||||
|  | @ -116,6 +132,7 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result<CommandResult> { | |||
|     let mut result = CommandResult::default(); | ||||
| 
 | ||||
|     match matches.subcommand() { | ||||
|         Some(("flags", matches)) => result = do_flags_command(state, matches), | ||||
|         Some(("load", matches)) => result = do_load_command(state, matches)?, | ||||
|         Some(("print", _matches)) => {} | ||||
|         Some(("quit", _matches)) => { | ||||
|  | @ -126,9 +143,8 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result<CommandResult> { | |||
|             println!("{}", state.position.to_fen_str()?); | ||||
|             result.should_print_position = false; | ||||
|         } | ||||
|         Some(("make", _matches)) => { | ||||
|             unimplemented!() | ||||
|         } | ||||
|         Some(("make", matches)) => result = do_make_command(state, matches)?, | ||||
|         Some(("perft", matches)) => result = do_perft_command(state, matches)?, | ||||
|         Some(("place", matches)) => { | ||||
|             let color = matches | ||||
|                 .get_one::<String>("color") | ||||
|  | @ -175,6 +191,34 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result<CommandResult> { | |||
|     Ok(result) | ||||
| } | ||||
| 
 | ||||
| fn do_flags_command(state: &mut State, _matches: &clap::ArgMatches) -> CommandResult { | ||||
|     let board = &state.position.board; | ||||
| 
 | ||||
|     println!("Castling:"); | ||||
| 
 | ||||
|     for (color, wing) in [ | ||||
|         (Color::White, Wing::KingSide), | ||||
|         (Color::White, Wing::QueenSide), | ||||
|         (Color::Black, Wing::KingSide), | ||||
|         (Color::Black, Wing::QueenSide), | ||||
|     ] { | ||||
|         let has_right = board.color_has_castling_right_unwrapped(color, wing); | ||||
|         let can_castle = board.color_can_castle(wing, Some(color)); | ||||
| 
 | ||||
|         let can_castle_message = match can_castle { | ||||
|             Ok(_) => "ok".to_string(), | ||||
|             Err(error) => format!("{error}"), | ||||
|         }; | ||||
| 
 | ||||
|         println!("  {color} {wing}: {has_right}, {can_castle_message}"); | ||||
|     } | ||||
| 
 | ||||
|     CommandResult { | ||||
|         should_continue: true, | ||||
|         should_print_position: false, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn do_load_command(state: &mut State, matches: &clap::ArgMatches) -> anyhow::Result<CommandResult> { | ||||
|     let fen_string = matches | ||||
|         .get_one::<String>("fen") | ||||
|  | @ -191,6 +235,26 @@ fn do_load_command(state: &mut State, matches: &clap::ArgMatches) -> anyhow::Res | |||
|     }) | ||||
| } | ||||
| 
 | ||||
| fn do_make_command(state: &mut State, matches: &clap::ArgMatches) -> anyhow::Result<CommandResult> { | ||||
|     let move_string = matches | ||||
|         .get_one::<String>("move") | ||||
|         .ok_or(CommandHandlingError::MissingArgument("move"))?; | ||||
| 
 | ||||
|     let algebraic_move: AlgebraicMoveComponents = move_string.parse()?; | ||||
| 
 | ||||
|     let encoded_move = state | ||||
|         .position | ||||
|         .move_from_algebraic_components(algebraic_move) | ||||
|         .ok_or(CommandHandlingError::ValueError { | ||||
|             argument_name: "move", | ||||
|             value: move_string.to_string(), | ||||
|         })?; | ||||
| 
 | ||||
|     state.position.make_move(encoded_move, ValidateMove::Yes)?; | ||||
| 
 | ||||
|     Ok(CommandResult::default()) | ||||
| } | ||||
| 
 | ||||
| fn do_reset_command( | ||||
|     state: &mut State, | ||||
|     matches: &clap::ArgMatches, | ||||
|  | @ -282,6 +346,25 @@ fn do_movement_command( | |||
|     }) | ||||
| } | ||||
| 
 | ||||
| fn do_perft_command( | ||||
|     state: &mut State, | ||||
|     matches: &clap::ArgMatches, | ||||
| ) -> anyhow::Result<CommandResult> { | ||||
|     let depth = *matches | ||||
|         .get_one::<usize>("depth") | ||||
|         .ok_or(CommandHandlingError::MissingArgument("depth"))?; | ||||
| 
 | ||||
|     let mut position = state.position.clone(); | ||||
|     let nodes_count = position.perft(depth); | ||||
| 
 | ||||
|     println!("nodes {nodes_count}"); | ||||
| 
 | ||||
|     Ok(CommandResult { | ||||
|         should_continue: true, | ||||
|         should_print_position: false, | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| fn do_zobrist_command(state: &mut State, _matches: &clap::ArgMatches) -> CommandResult { | ||||
|     if let Some(hash) = state.position.zobrist_hash() { | ||||
|         println!("hash:{hash}"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue