use std::error::Error;
use std::fmt::Display;
use std::str::FromStr;
use crate::rank::Rank;
use crate::side::Side;
use crate::square::{self, Square};
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Color {
White,
Black,
}
impl Color {
pub fn opponent(self) -> Color {
match self {
Self::White => Self::Black,
Self::Black => Self::White,
}
}
pub fn castle_square(self, side: Side) -> Square {
match (self, side) {
(Color::White, Side::King) => square::H1,
(Color::White, Side::Queen) => square::A1,
(Color::Black, Side::King) => square::H8,
(Color::Black, Side::Queen) => square::A8,
}
}
pub fn back_rank(self) -> Rank {
match self {
Self::White => Rank::First,
Self::Black => Rank::Eighth,
}
}
pub fn second_rank(self) -> Rank {
match self {
Self::White => Rank::Second,
Self::Black => Rank::Seventh,
}
}
pub fn fourth_rank(self) -> Rank {
match self {
Self::White => Rank::Fourth,
Self::Black => Rank::Fifth,
}
}
pub fn seventh_rank(self) -> Rank {
match self {
Self::White => Rank::Seventh,
Self::Black => Rank::Second,
}
}
pub fn as_str(self) -> &'static str {
match self {
Self::White => "white",
Self::Black => "black",
}
}
}
impl FromStr for Color {
type Err = ParseColorError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let lowered = s.to_lowercase();
match lowered.as_str() {
"w" | "white" => Ok(Self::White),
"b" | "black" => Ok(Self::Black),
_ => Err(ParseColorError(lowered)),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ParseColorError(String);
impl Display for ParseColorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid color string: {}", self.0)
}
}
impl Error for ParseColorError {}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ByColor<T> {
pub white: T,
pub black: T,
}
impl<T> ByColor<T> {
pub fn new(white: T, black: T) -> Self {
Self { white, black }
}
pub fn get(&self, c: Color) -> &T {
match c {
Color::White => &self.white,
Color::Black => &self.black,
}
}
#[must_use]
pub fn set(self, c: Color, value: T) -> Self {
match c {
Color::White => Self {
white: value,
..self
},
Color::Black => Self {
black: value,
..self
},
}
}
#[must_use]
pub fn update<F>(self, c: Color, f: F) -> Self
where
F: Fn(T) -> T,
{
match c {
Color::White => Self {
white: f(self.white),
..self
},
Color::Black => Self {
black: f(self.black),
..self
},
}
}
pub fn foreach<F>(&self, mut f: F)
where
F: FnMut(&T),
{
f(&self.white);
f(&self.black);
}
pub fn map<F>(&self, f: F) -> Self
where
F: Fn(&T) -> T,
{
Self {
white: f(&self.white),
black: f(&self.black),
}
}
pub fn from<F>(f: F) -> Self
where
F: Fn(Color) -> T,
{
Self {
white: f(Color::White),
black: f(Color::Black),
}
}
pub fn find<F>(&self, f: F) -> Option<(Color, &T)>
where
F: Fn(&T) -> bool,
{
if f(&self.white) {
Some((Color::White, &self.white))
} else if f(&self.black) {
Some((Color::Black, &self.black))
} else {
None
}
}
}
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}