This commit is contained in:
Eryn Wells 2025-05-08 17:37:51 -07:00
parent d5cdf273c8
commit 091cc99cb3
42 changed files with 805 additions and 1662 deletions

View file

@ -1,6 +1,6 @@
// Eryn Wells <eryn@erynwells.me>
use crate::{errors::TryFromCharError, try_from_string};
use crate::{errors::TryFromCharError, try_from_string, Direction};
use std::fmt;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
@ -21,6 +21,7 @@ impl Color {
Color::ALL.iter()
}
#[must_use]
pub fn into_iter() -> std::array::IntoIter<Color, { Self::NUM }> {
Color::ALL.into_iter()
}
@ -33,6 +34,20 @@ impl Color {
Color::Black => Color::White,
}
}
/// "Forward" direction of pawn pushes for this color.
#[must_use]
pub fn push_direction(&self) -> Direction {
match self {
Color::White => Direction::North,
Color::Black => Direction::South,
}
}
#[must_use]
pub const fn next(&self) -> Color {
Self::ALL[((*self as usize) + 1) % Self::NUM]
}
}
impl fmt::Display for Color {

View file

@ -217,6 +217,43 @@ coordinate_enum!(Square, [
A8, B8, C8, D8, E8, F8, G8, H8
]);
/// Generate an enum that maps its values to variants of [Square].
macro_rules! to_square_enum {
($vis:vis $name:ident { $($variant:ident)* }) => {
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
$vis enum $name {
$($variant = Square::$variant as u8,)*
}
impl From<$name> for Square {
fn from(value: $name) -> Self {
unsafe { Square::from_index_unchecked(value as u8) }
}
}
};
}
to_square_enum!(
pub EnPassantTargetSquare {
A3 B3 C3 D3 E3 F3 G3 H3
A6 B6 C6 D6 E6 F6 G6 H6
}
);
// impl TryFrom<Square> for EnPassantTargetSquare {
// type Error = ();
// fn try_from(value: Square) -> Result<Self, Self::Error> {
// let square = Self::ALL[value as usize];
// if square as usize == value as usize {
// Ok(square)
// } else {
// Err(())
// }
// }
// }
impl Square {
/// # Safety
///
@ -240,20 +277,24 @@ impl Square {
s.parse()
}
#[must_use]
#[inline]
pub fn file(self) -> File {
unsafe { File::new_unchecked((self as u8) & 0b000_00111) }
}
#[must_use]
#[inline]
pub fn rank(self) -> Rank {
unsafe { Rank::new_unchecked((self as u8) >> 3) }
}
#[must_use]
pub fn file_rank(&self) -> (File, Rank) {
(self.file(), self.rank())
}
#[must_use]
pub fn neighbor(self, direction: Direction) -> Option<Square> {
let index: u8 = self as u8;
let dir: i8 = direction.to_offset();
@ -347,10 +388,9 @@ impl From<File> for char {
}
}
impl Into<char> for Rank {
fn into(self) -> char {
let value: u8 = self.into();
(value + b'1') as char
impl From<Rank> for char {
fn from(value: Rank) -> Self {
Self::from(value.0)
}
}

View file

@ -3,6 +3,34 @@
use crate::{errors::TryFromCharError, try_from_string, Color, Square};
use std::{array, fmt, slice};
trait _Shape {
fn symbol(&self) -> char;
fn index(&self) -> usize;
}
macro_rules! shape {
($name:ident, $index:expr, $symbol:expr) => {
struct $name;
impl _Shape for $name {
fn symbol(&self) -> char {
$symbol
}
fn index(&self) -> usize {
$index
}
}
};
}
shape!(Pawn, 0, 'P');
shape!(Knight, 1, 'K');
shape!(Bishop, 2, 'B');
shape!(Rook, 3, 'R');
shape!(Queen, 4, 'Q');
shape!(King, 5, 'K');
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Shape {
Pawn = 0,
@ -94,8 +122,8 @@ impl fmt::Display for Shape {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Piece {
color: Color,
shape: Shape,
pub color: Color,
pub shape: Shape,
}
macro_rules! piece_constructor {
@ -132,16 +160,6 @@ impl Piece {
piece_constructor!(queen, Queen);
piece_constructor!(king, King);
#[must_use]
pub fn color(&self) -> Color {
self.color
}
#[must_use]
pub fn shape(&self) -> Shape {
self.shape
}
is_shape!(is_pawn, Pawn);
is_shape!(is_knight, Knight);
is_shape!(is_bishop, Bishop);
@ -195,10 +213,11 @@ impl From<&PlacedPiece> for Piece {
}
}
#[deprecated]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PlacedPiece {
piece: Piece,
square: Square,
pub piece: Piece,
pub square: Square,
}
macro_rules! is_shape {
@ -223,27 +242,6 @@ impl PlacedPiece {
self.piece
}
/// The square the piece is on
#[inline]
#[must_use]
pub fn square(&self) -> Square {
self.square
}
/// The piece's [Color]
#[inline]
#[must_use]
pub fn color(&self) -> Color {
self.piece.color
}
/// The piece's [Shape]
#[inline]
#[must_use]
pub fn shape(&self) -> Shape {
self.piece.shape
}
is_shape!(is_pawn, Pawn);
is_shape!(is_knight, Knight);
is_shape!(is_bishop, Bishop);
@ -254,7 +252,7 @@ impl PlacedPiece {
#[must_use]
pub fn is_kingside_rook(&self) -> bool {
self.is_rook()
&& match self.color() {
&& match self.piece.color {
Color::White => self.square == Square::H1,
Color::Black => self.square == Square::H8,
}
@ -263,7 +261,7 @@ impl PlacedPiece {
#[must_use]
pub fn is_queenside_rook(&self) -> bool {
self.is_rook()
&& match self.color() {
&& match self.piece.color {
Color::White => self.square == Square::A1,
Color::Black => self.square == Square::A8,
}
@ -294,6 +292,6 @@ mod tests {
#[test]
fn shape_into_char() {
assert_eq!(<Shape as Into<char>>::into(Shape::Pawn) as char, 'P');
assert_eq!(<Shape as Into<char>>::into(Shape::Pawn), 'P');
}
}