chessfriend/explorer/src/main.rs

119 lines
3.5 KiB
Rust
Raw Normal View History

use board::piece::{Color, Piece, Shape};
2024-01-24 09:15:18 -08:00
use board::Position;
use chessfriend_core::Square;
use clap::{Arg, Command};
use rustyline::error::ReadlineError;
use rustyline::DefaultEditor;
#[derive(Eq, PartialEq)]
enum ShouldContinue {
Yes,
No,
}
fn command_line() -> Command {
// strip out usage
const PARSER_TEMPLATE: &str = "\
{all-args}
";
// strip out name/version
const APPLET_TEMPLATE: &str = "\
{about-with-newline}\n\
{usage-heading}\n {usage}\n\
\n\
{all-args}{after-help}\
";
Command::new("explorer")
.multicall(true)
.arg_required_else_help(true)
.subcommand_required(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.help_template(PARSER_TEMPLATE)
.subcommand(Command::new("print").about("Print the board"))
.subcommand(
Command::new("place")
.arg(Arg::new("piece").required(true))
.arg(Arg::new("square").required(true)),
)
.subcommand(Command::new("quit").about("Quit the program"))
}
fn respond(line: &str, pos: &mut Position) -> Result<ShouldContinue, String> {
let args = shlex::split(line).ok_or("error: Invalid quoting")?;
let matches = command_line()
.try_get_matches_from(args)
.map_err(|e| e.to_string())?;
match matches.subcommand() {
Some(("print", _matches)) => {}
Some(("quit", _matches)) => {
return Ok(ShouldContinue::No);
}
Some(("place", _matches)) => {
let piece_arg = _matches.get_one::<String>("piece").unwrap();
let shape = match piece_arg.chars().nth(0) {
Some(c) => Shape::try_from(c).map_err(|_| ()),
None => Err(()),
}
.map_err(|_| "Error: invalid piece specifier")?;
let square_arg = _matches.get_one::<String>("square").unwrap();
let square = Square::from_algebraic_str(square_arg)
.map_err(|_| "Error: invalid square specifier")?;
pos.place_piece(&Piece::new(Color::White, shape), &square)
.map_err(|_| "Error: Unable to place piece")?;
}
Some((name, _matches)) => unimplemented!("{name}"),
None => unreachable!("Subcommand required"),
}
Ok(ShouldContinue::Yes)
}
fn main() -> Result<(), String> {
let mut editor = DefaultEditor::new().map_err(|err| format!("Error: {}", err.to_string()))?;
let mut pos = Position::empty();
loop {
println!("{}", &pos);
let readline = editor.readline("? ");
match readline {
Ok(line) => {
let line = line.trim();
if line.is_empty() {
continue;
}
match respond(line, &mut pos) {
Ok(should_continue) => {
if should_continue == ShouldContinue::No {
break;
}
}
Err(message) => println!("{}", message),
}
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break;
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
Ok(())
}