chess-lib 0.1.3

A chess movement generator library.
Documentation
use chess_lib::{generate_slider_moves, run_perft};

use clap::{arg, Command};
use regex::Regex;

fn cli() -> Command {
    Command::new("engine")
        .about("The underlying backend which powers the bot games")
        .subcommand_required(true)
        .arg_required_else_help(true)
        .subcommand(
            Command::new("chess")
                .about("Chess engine")
                .subcommand_required(true)
                .arg_required_else_help(true)
                .subcommand(Command::new("interactive").about("Run interactive mode"))
                .subcommand(
                    Command::new("perft")
                        .about("Run perft")
                        .arg(
                            arg!(-f --fen <FEN>)
                                .required(true)
                                .value_parser(clap::value_parser!(String)),
                        )
                        .arg(
                            arg!(-d --depth <DEPTH>)
                                .required(true)
                                .value_parser(clap::value_parser!(usize)),
                        )
                        .arg(
                            arg!(-m --moves <MOVES>)
                                .required(false)
                                .default_value("")
                                .value_parser(clap::value_parser!(String)),
                        ),
                )
                .subcommand(Command::new("generate").about("Generate code for slider moves")),
        )
}

fn main() {
    let matches = cli().get_matches();

    match matches.subcommand() {
        Some(("chess", chess_matches)) => match chess_matches.subcommand() {
            Some(("perft", perft_matches)) => {
                let depth = perft_matches.get_one::<usize>("depth").unwrap();
                let fen = perft_matches.get_one::<String>("fen").unwrap();
                let moves = perft_matches.get_one::<String>("moves").unwrap();
                let moves = moves
                    .split(' ')
                    .filter(|s| !s.is_empty())
                    .collect::<Vec<&str>>();

                run_perft(*depth, fen, moves);
            }
            Some(("interactive", _)) => loop {
                let mut input = String::new();
                std::io::stdin()
                    .read_line(&mut input)
                    .expect("Failed to read line");

                let input = input.trim();
                if input == "quit" {
                    break;
                }

                let re_perft =
                    Regex::new(r"perft depth (\d+) position fen (.*) moves( (.+))?").unwrap();

                if let Some(captures) = re_perft.captures(input) {
                    let depth = captures
                        .get(1)
                        .map_or(1, |m| m.as_str().parse::<usize>().unwrap());
                    let fen = captures.get(2).map_or("", |m| m.as_str());
                    let moves = captures.get(3).map_or("", |m| m.as_str());
                    let moves_vec: Vec<&str> = moves.split_whitespace().collect::<Vec<&str>>();

                    let result = run_perft(depth, fen, moves_vec);
                    println!("Nodes searched: {}", result);
                }
            },
            Some(("generate", _)) => generate_slider_moves(),
            _ => unreachable!(),
        },
        _ => unreachable!(),
    }
}