mod fen;
#[allow(dead_code)]
mod go;
use crate::physical::*;
pub trait ToUCI {
fn generate(&self) -> String;
}
pub trait FromUCI {
fn parse(representation: String, current_board: &mut Board) -> Result<Box<dyn Action>, ()>;
}
impl ToUCI for Move {
fn generate(&self) -> String {
let mut repr = format!("{}{}", self.from, self.to);
if let Some(promotion) = self.promotion {
repr.push(promotion.letter());
}
repr
}
}
#[allow(refining_impl_trait)]
impl FromUCI for Move {
fn parse(mut representation: String, current_board: &mut Board) -> Result<Box<dyn Action>, ()> {
if representation.len() > 5 || representation.len() < 4 || representation.contains(" ") {
return Err(());
}
let from = Coordinate::from(&mut representation)?;
if !from.is_valid() {
return Err(())
}
let to = Coordinate::from(&mut representation)?;
if !to.is_valid() {
return Err(())
}
let promotion = if !representation.is_empty() {
board::PieceType::from(representation.remove(0)).ok()
} else {
None
};
Ok(Box::new(Self::new(
from,
to,
current_board,
promotion,
true,
)))
}
}
#[allow(refining_impl_trait)]
impl FromUCI for Castle {
fn parse(mut representation: String, current_board: &mut Board) -> Result<Box<dyn Action>, ()> {
if representation.chars().nth(0).unwrap() != 'e'
|| representation.len() != 4
|| representation.contains(" ")
{
return Err(());
}
let king_loc = Coordinate::from(&mut representation)?;
if !king_loc.is_valid() {
return Err(())
}
let king_target = Coordinate::from(&mut representation)?;
if !king_target.is_valid() {
return Err(())
}
let player = match king_loc.row {
0 => board::Color::White,
7 => board::Color::Black,
_ => {
return Err(());
}
};
let side = match king_target.col {
2 => CastleSide::QueenSide,
6 => CastleSide::KingSide,
_ => return Err(()),
};
let mut castle = Self::new(side, player);
if castle.is_illegal(current_board) {
return Err(());
}
Ok(Box::new(castle))
}
}
impl ToUCI for Castle {
fn generate(&self) -> String {
let row = self.player.home_rank() + 1;
let target = board::LETTERS
.chars()
.nth(self.side.king_end_col())
.unwrap();
format!("e{row}{target}{row}")
}
}
pub fn parse_action(representation: String, current_board: &mut Board) -> Box<dyn Action> {
let castle = Castle::parse(representation.clone(), current_board);
if let Ok(c) = castle {
return c;
}
let m = Move::parse(representation, current_board).unwrap();
m
}
pub fn safe_parse_action(
representation: String,
current_board: &mut Board,
) -> Result<Box<dyn Action>, ()> {
if let Ok(c) = Castle::parse(representation.clone(), current_board) {
return Ok(c);
}
if let Ok(m) = Move::parse(representation, current_board) {
return Ok(m);
}
Err(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_move() {
let b: Board = Default::default();
let expected = String::from("e2e4q");
let m = Move::new(
Coordinate::new(4, 1),
Coordinate::new(4, 3),
&b,
Some(board::PieceType::Queen),
false,
);
let generated = m.generate();
assert_eq!(expected, generated);
}
#[test]
fn generate_castle() {
let expected = String::from("e8g8");
let generated = Castle::new(CastleSide::KingSide, board::Color::Black).generate();
assert_eq!(generated, expected);
}
}