[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