use std::iter::FromIterator;
use std::ops;
use crate::bitboard::BitBoard;
use crate::pieces::Piece;
use crate::square::Square;
use crate::Side;
use anyhow::anyhow;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum CastleZone {
WK,
WQ,
BK,
BQ,
}
impl Display for CastleZone {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
CastleZone::WK => "wk",
CastleZone::WQ => "wq",
CastleZone::BK => "bk",
CastleZone::BQ => "bq",
}
)
}
}
impl FromStr for CastleZone {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"wk" | "WK" => Ok(CastleZone::WK),
"wq" | "WQ" => Ok(CastleZone::WQ),
"bk" | "BK" => Ok(CastleZone::BK),
"bq" | "BQ" => Ok(CastleZone::BQ),
_ => Err(anyhow!("Cannot parse {} as CastleZone", s)),
}
}
}
impl CastleZone {
pub fn kingside(side: Side) -> CastleZone {
match side {
Side::White => CastleZone::WK,
Side::Black => CastleZone::BK,
}
}
pub fn queenside(side: Side) -> CastleZone {
match side {
Side::White => CastleZone::WQ,
Side::Black => CastleZone::BQ,
}
}
pub fn iter() -> impl Iterator<Item = CastleZone> {
[
CastleZone::WK,
CastleZone::WQ,
CastleZone::BK,
CastleZone::BQ,
]
.iter()
.cloned()
}
pub fn source_squares(self) -> BitBoard {
match self {
CastleZone::WK => Square::E1 | Square::H1,
CastleZone::WQ => Square::E1 | Square::A1,
CastleZone::BK => Square::E8 | Square::H8,
CastleZone::BQ => Square::E8 | Square::A8,
}
}
pub fn rook_data(self) -> (Piece, Square, Square) {
match self {
CastleZone::WK => (Piece::WR, Square::H1, Square::F1),
CastleZone::BK => (Piece::BR, Square::H8, Square::F8),
CastleZone::WQ => (Piece::WR, Square::A1, Square::D1),
CastleZone::BQ => (Piece::BR, Square::A8, Square::D8),
}
}
pub fn king_data(self) -> (Piece, Square, Square) {
match self {
CastleZone::WK => (Piece::WK, Square::E1, Square::G1),
CastleZone::BK => (Piece::BK, Square::E8, Square::G8),
CastleZone::WQ => (Piece::WK, Square::E1, Square::C1),
CastleZone::BQ => (Piece::BK, Square::E8, Square::C8),
}
}
pub fn unoccupied_requirement(self) -> BitBoard {
match self {
CastleZone::WK => Square::F1 | Square::G1,
CastleZone::WQ => Square::B1 | Square::C1 | Square::D1,
CastleZone::BK => Square::F8 | Square::G8,
CastleZone::BQ => Square::B8 | Square::C8 | Square::D8,
}
}
pub fn uncontrolled_requirement(self) -> BitBoard {
match self {
CastleZone::WK => Square::E1 | Square::F1 | Square::G1,
CastleZone::WQ => Square::E1 | Square::C1 | Square::D1,
CastleZone::BK => Square::E8 | Square::F8 | Square::G8,
CastleZone::BQ => Square::E8 | Square::C8 | Square::D8,
}
}
pub fn lift(self) -> CastleZoneSet {
CastleZoneSet {
data: 1usize << self as usize,
}
}
}
#[cfg(test)]
mod test {
use crate::CastleZone;
#[test]
fn display() {
assert_eq!("wk", CastleZone::WK.to_string().as_str());
assert_eq!("wq", CastleZone::WQ.to_string().as_str());
assert_eq!("bk", CastleZone::BK.to_string().as_str());
assert_eq!("bq", CastleZone::BQ.to_string().as_str());
}
#[test]
fn from_str() {
assert_eq!(CastleZone::WK, "wk".parse().unwrap());
assert_eq!(CastleZone::WK, "WK".parse().unwrap());
assert_eq!(CastleZone::WQ, "wq".parse().unwrap());
assert_eq!(CastleZone::WQ, "WQ".parse().unwrap());
assert_eq!(CastleZone::BK, "bk".parse().unwrap());
assert_eq!(CastleZone::BK, "BK".parse().unwrap());
assert_eq!(CastleZone::BQ, "bq".parse().unwrap());
assert_eq!(CastleZone::BQ, "BQ".parse().unwrap());
}
}
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq)]
pub struct CastleZoneSet {
data: usize,
}
impl CastleZoneSet {
pub fn contains(self, zone: CastleZone) -> bool {
(1usize << zone as usize) & self.data != 0
}
pub fn intersects(self, other: CastleZoneSet) -> bool {
other.iter().any(|z| self.contains(z))
}
pub fn iter(self) -> impl Iterator<Item = CastleZone> {
CastleZone::iter().filter(move |&z| self.contains(z))
}
pub const ALL: CastleZoneSet = CastleZoneSet { data: 0b1111 };
pub const NONE: CastleZoneSet = CastleZoneSet { data: 0 };
pub const WHITE: CastleZoneSet = CastleZoneSet { data: 0b11 };
pub const BLACK: CastleZoneSet = CastleZoneSet { data: 0b1100 };
pub const WK: CastleZoneSet = CastleZoneSet { data: 0b1 };
pub const WQ: CastleZoneSet = CastleZoneSet { data: 0b10 };
pub const BK: CastleZoneSet = CastleZoneSet { data: 0b100 };
pub const BQ: CastleZoneSet = CastleZoneSet { data: 0b1000 };
}
impl FromIterator<CastleZone> for CastleZoneSet {
fn from_iter<T: IntoIterator<Item = CastleZone>>(iter: T) -> Self {
CastleZoneSet {
data: iter
.into_iter()
.map(|cz| 1usize << cz as usize)
.fold(0, |a, b| a | b),
}
}
}
impl ops::Sub<CastleZoneSet> for CastleZoneSet {
type Output = CastleZoneSet;
fn sub(self, rhs: CastleZoneSet) -> Self::Output {
CastleZoneSet {
data: self.data & !rhs.data,
}
}
}
impl ops::SubAssign<CastleZoneSet> for CastleZoneSet {
fn sub_assign(&mut self, rhs: CastleZoneSet) {
self.data &= !rhs.data
}
}
impl ops::BitOr<CastleZoneSet> for CastleZoneSet {
type Output = CastleZoneSet;
fn bitor(self, rhs: CastleZoneSet) -> Self::Output {
CastleZoneSet {
data: self.data | rhs.data,
}
}
}
impl ops::BitAnd<CastleZoneSet> for CastleZoneSet {
type Output = CastleZoneSet;
fn bitand(self, rhs: CastleZoneSet) -> Self::Output {
CastleZoneSet {
data: self.data & rhs.data,
}
}
}
#[cfg(test)]
mod set_test {
use super::*;
#[test]
fn test_all() {
let all = CastleZoneSet::ALL;
for zone in CastleZone::iter() {
assert!(all.contains(zone));
}
}
#[test]
fn test_none() {
let none = CastleZoneSet::NONE;
for zone in CastleZone::iter() {
assert!(!none.contains(zone));
}
}
#[test]
fn test_collect() {
let source = vec![
CastleZone::BK,
CastleZone::WK,
CastleZone::WQ,
CastleZone::BQ,
];
let collected: CastleZoneSet = source.into_iter().collect();
assert_eq!(CastleZoneSet::ALL, collected);
}
}