chess-lib 0.1.3

A chess movement generator library.
Documentation
use crate::engine::bitboard::Bitboard;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn opposite(&self) -> Self {
        match self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }

    pub fn iter() -> impl Iterator<Item = Color> {
        [Color::White, Color::Black].iter().copied()
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Piece {
    Pawn,
    Knight,
    Bishop,
    Rook,
    Queen,
    King,
}

impl Piece {
    pub fn iter() -> impl Iterator<Item = Piece> {
        [
            Piece::Pawn,
            Piece::Knight,
            Piece::Bishop,
            Piece::Rook,
            Piece::Queen,
            Piece::King,
        ]
        .iter()
        .copied()
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Promotion {
    Knight,
    Bishop,
    Rook,
    Queen,
}

impl Promotion {
    pub fn into_piece(self) -> Piece {
        match self {
            Promotion::Knight => Piece::Knight,
            Promotion::Bishop => Piece::Bishop,
            Promotion::Rook => Piece::Rook,
            Promotion::Queen => Piece::Queen,
        }
    }

    pub fn from_char(c: char) -> Option<Self> {
        match c {
            'n' => Some(Promotion::Knight),
            'b' => Some(Promotion::Bishop),
            'r' => Some(Promotion::Rook),
            'q' => Some(Promotion::Queen),
            _ => None,
        }
    }
}

impl std::fmt::Display for Promotion {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Promotion::Knight => write!(f, "n"),
            Promotion::Bishop => write!(f, "b"),
            Promotion::Rook => write!(f, "r"),
            Promotion::Queen => write!(f, "q"),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ChessMan {
    pub color: Color,
    pub piece: Piece,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum File {
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
}

impl File {
    pub fn from_char(c: char) -> Option<Self> {
        match c {
            'a' => Some(File::A),
            'b' => Some(File::B),
            'c' => Some(File::C),
            'd' => Some(File::D),
            'e' => Some(File::E),
            'f' => Some(File::F),
            'g' => Some(File::G),
            'h' => Some(File::H),
            _ => None,
        }
    }

    pub fn index(&self) -> i8 {
        *self as i8
    }

    pub fn from_index(index: i8) -> Self {
        match index {
            1 => File::A,
            2 => File::B,
            3 => File::C,
            4 => File::D,
            5 => File::E,
            6 => File::F,
            7 => File::G,
            8 => File::H,
            _ => unreachable!("File does not exists for this index"),
        }
    }

    pub fn iter() -> impl Iterator<Item = Self> {
        [
            File::A,
            File::B,
            File::C,
            File::D,
            File::E,
            File::F,
            File::G,
            File::H,
        ]
        .iter()
        .copied()
    }
}

impl std::fmt::Display for File {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let c = match self {
            File::A => 'a',
            File::B => 'b',
            File::C => 'c',
            File::D => 'd',
            File::E => 'e',
            File::F => 'f',
            File::G => 'g',
            File::H => 'h',
        };
        write!(f, "{}", c)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Rank {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
}

impl Rank {
    pub fn from_char(c: char) -> Option<Self> {
        match c {
            '1' => Some(Rank::One),
            '2' => Some(Rank::Two),
            '3' => Some(Rank::Three),
            '4' => Some(Rank::Four),
            '5' => Some(Rank::Five),
            '6' => Some(Rank::Six),
            '7' => Some(Rank::Seven),
            '8' => Some(Rank::Eight),
            _ => None,
        }
    }

    pub fn index(&self) -> i8 {
        *self as i8
    }

    pub fn from_index(index: i8) -> Self {
        match index {
            1 => Rank::One,
            2 => Rank::Two,
            3 => Rank::Three,
            4 => Rank::Four,
            5 => Rank::Five,
            6 => Rank::Six,
            7 => Rank::Seven,
            8 => Rank::Eight,
            _ => unreachable!("Rank does not exists for this index"),
        }
    }

    pub fn iter() -> impl Iterator<Item = Self> {
        [
            Rank::One,
            Rank::Two,
            Rank::Three,
            Rank::Four,
            Rank::Five,
            Rank::Six,
            Rank::Seven,
            Rank::Eight,
        ]
        .iter()
        .copied()
    }
}

impl std::fmt::Display for Rank {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let n = match self {
            Rank::One => 1,
            Rank::Two => 2,
            Rank::Three => 3,
            Rank::Four => 4,
            Rank::Five => 5,
            Rank::Six => 6,
            Rank::Seven => 7,
            Rank::Eight => 8,
        };
        write!(f, "{}", n)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Square {
    pub file: File,
    pub rank: Rank,
}

impl Square {
    pub fn new(file: File, rank: Rank) -> Self {
        Self { file, rank }
    }

    pub fn from_str(s: &str) -> Option<Self> {
        let mut chars = s.chars();
        let file = File::from_char(chars.next()?)?;
        let rank = Rank::from_char(chars.next()?)?;
        if chars.next().is_some() {
            return None;
        }
        Some(Self::new(file, rank))
    }

    pub fn bitboard(&self) -> Bitboard {
        (0b1 << self.file.index()) << (8 * self.rank.index())
    }

    pub fn try_offset(&self, file_offset: i8, rank_offset: i8) -> Option<Self> {
        let file = File::iter().nth((self.file.index() + file_offset) as usize)?;
        let rank = Rank::iter().nth((self.rank.index() + rank_offset) as usize)?;

        Some(Self::new(file, rank))
    }

    pub fn index(&self) -> i8 {
        self.file.index() + 8 * self.rank.index()
    }

    pub fn iter() -> impl Iterator<Item = Self> {
        Rank::iter().flat_map(|rank| File::iter().map(move |file| Self::new(file, rank)))
    }
}

impl std::fmt::Display for Square {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}{}", self.file, self.rank)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Move {
    pub from: Square,
    pub to: Square,
    pub promotion: Option<Promotion>,
}

impl Move {
    pub fn new(from: Square, to: Square, promotion: Option<Promotion>) -> Self {
        Self {
            from,
            to,
            promotion,
        }
    }
}

impl std::fmt::Display for Move {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.promotion.is_some() {
            write!(f, "{}{}{}", self.from, self.to, self.promotion.unwrap())
        } else {
            write!(f, "{}{}", self.from, self.to)
        }
    }
}