use chess_notation_parser::{Flag, FlagCheck, Piece, Turn};
use chess_turn_engine::ChessTurnEngine;
use rand::seq::SliceRandom;
use std::fmt;
use std::str::FromStr;
pub enum Player {
Random,
Aggressive,
Pacifist,
SemiPacifist,
}
impl Player {
pub fn decide_next_turn(&self, game: &ChessTurnEngine) -> String {
const PAWN_CAN_ATTACK_PAWNS: bool = true;
match self {
Self::Random => find_random_turn(game),
Self::Aggressive => find_aggressive_turn(game),
Self::SemiPacifist => {
find_pieceful_turn(game, PAWN_CAN_ATTACK_PAWNS)
}
Self::Pacifist => find_pieceful_turn(game, !PAWN_CAN_ATTACK_PAWNS),
}
}
}
impl fmt::Display for Player {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Random => "Random",
Self::Aggressive => "Aggressive",
Self::Pacifist => "Pacifist",
Self::SemiPacifist => "SemiPacifist",
}
)
}
}
impl FromStr for Player {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Random" => Ok(Self::Random),
"Aggressive" => Ok(Self::Aggressive),
"Pacifist" => Ok(Self::Pacifist),
"SemiPacifist" => Ok(Self::SemiPacifist),
_ => Err("Invalid player input"),
}
}
}
fn all_turns(game: &ChessTurnEngine) -> Vec<String> {
game.available_turns()
.into_iter()
.map(|turn| String::from(turn.get_turn()))
.collect::<Vec<String>>()
}
fn get_pawn_capture_other_pawns_turns(game: &ChessTurnEngine) -> Vec<String> {
game.available_turns()
.into_iter()
.filter(|avail_turn| {
match Turn::try_from(avail_turn.get_turn().as_ref()).unwrap() {
Turn::Move(turn) => {
turn.check_flag(Flag::CAPTURE)
&& !turn.check_flag(Flag::CHECKMATE)
&& turn.who == Piece::Pawn
&& avail_turn.captured == Some(String::from("Pawn"))
}
_ => false,
}
})
.map(|turn| String::from(turn.get_turn()))
.collect::<Vec<String>>()
}
fn get_all_pieceful_turns(game: &ChessTurnEngine) -> Vec<String> {
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
!turn.is_capture()
})
.collect::<Vec<String>>()
}
fn get_all_pieceful_checkmate_turns(game: &ChessTurnEngine) -> Vec<String> {
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
turn.is_checkmate() && !turn.is_capture()
})
.collect::<Vec<String>>()
}
fn get_all_checkmate_turns(game: &ChessTurnEngine) -> Vec<String> {
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
turn.is_checkmate()
})
.collect::<Vec<String>>()
}
fn get_all_check_turns(game: &ChessTurnEngine) -> Vec<String> {
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
turn.is_check()
})
.collect::<Vec<String>>()
}
fn get_all_pieceful_with_check_turns(game: &ChessTurnEngine) -> Vec<String> {
let checkmate = all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
!turn.is_capture() && !turn.is_check() && turn.is_checkmate()
})
.collect::<Vec<String>>();
if checkmate.is_empty() {
return checkmate;
}
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
!turn.is_capture() && !turn.is_check()
})
.collect::<Vec<String>>()
}
fn get_capture_turns(game: &ChessTurnEngine) -> Vec<String> {
all_turns(&game)
.into_iter()
.filter(|turn| {
let turn = Turn::try_from(turn.as_ref()).unwrap();
turn.is_capture() && !turn.is_checkmate()
})
.collect::<Vec<String>>()
}
fn find_pieceful_turn(
game: &ChessTurnEngine,
pawns_can_attack_pawns: bool,
) -> String {
let turns = get_all_pieceful_checkmate_turns(game);
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
let mut turns = get_all_pieceful_turns(game);
if pawns_can_attack_pawns {
let mut pawns_capture_turns = get_pawn_capture_other_pawns_turns(game);
turns.append(&mut pawns_capture_turns);
}
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
let turns = get_all_pieceful_with_check_turns(game);
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
let turns = get_capture_turns(game);
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
all_turns(&game)
.choose(&mut rand::thread_rng())
.unwrap()
.clone()
}
fn find_aggressive_turn(game: &ChessTurnEngine) -> String {
let turns = get_all_checkmate_turns(game);
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
let mut turns = get_all_check_turns(game);
let mut capture_turns = get_capture_turns(game);
turns.append(&mut capture_turns);
if !turns.is_empty() {
return turns.choose(&mut rand::thread_rng()).unwrap().clone();
}
all_turns(&game)
.choose(&mut rand::thread_rng())
.unwrap()
.clone()
}
fn find_random_turn(game: &ChessTurnEngine) -> String {
all_turns(&game)
.choose(&mut rand::thread_rng())
.unwrap()
.clone()
}