[core,board] Move board::piece to core
Break up types in core into finer grained modules. Update all the imports.
This commit is contained in:
parent
6f85305912
commit
8b2a3926b3
25 changed files with 235 additions and 227 deletions
62
core/src/colors.rs
Normal file
62
core/src/colors.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::try_from_string;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum TryFromError {
|
||||
InvalidCharacter,
|
||||
ZeroLengthString,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Color {
|
||||
White = 0,
|
||||
Black = 1,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn iter() -> impl Iterator<Item = Color> {
|
||||
[Color::White, Color::Black].into_iter()
|
||||
}
|
||||
|
||||
pub fn other(&self) -> Color {
|
||||
match self {
|
||||
Color::White => Color::Black,
|
||||
Color::Black => Color::White,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Color::White
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Color::White => "White",
|
||||
Color::Black => "Black",
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<char> for Color {
|
||||
type Error = TryFromError;
|
||||
|
||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
'w' | 'W' => Ok(Color::White),
|
||||
'b' | 'B' => Ok(Color::Black),
|
||||
_ => Err(TryFromError::InvalidCharacter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try_from_string!(Color);
|
7
core/src/errors.rs
Normal file
7
core/src/errors.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TryFromCharError;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TryFromStrError;
|
|
@ -1,3 +1,12 @@
|
|||
mod coordinates;
|
||||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
pub mod colors;
|
||||
pub mod coordinates;
|
||||
pub mod errors;
|
||||
pub mod pieces;
|
||||
|
||||
mod macros;
|
||||
|
||||
pub use colors::Color;
|
||||
pub use coordinates::{Direction, File, Rank, Square};
|
||||
pub use pieces::{Piece, PlacedPiece, Shape};
|
||||
|
|
32
core/src/macros.rs
Normal file
32
core/src/macros.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! try_from_string {
|
||||
($type:ty) => {
|
||||
try_from_string!($type, &str);
|
||||
try_from_string!($type, &String);
|
||||
};
|
||||
($type:ty, $from_type:ty) => {
|
||||
impl TryFrom<$from_type> for $type {
|
||||
type Error = $crate::errors::TryFromStrError;
|
||||
|
||||
fn try_from(value: $from_type) -> Result<Self, Self::Error> {
|
||||
let first_char = value
|
||||
.chars()
|
||||
.nth(0)
|
||||
.ok_or($crate::errors::TryFromStrError)?;
|
||||
Self::try_from(first_char).map_err(|_| $crate::errors::TryFromStrError)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! piece {
|
||||
($color:ident $shape:ident) => {
|
||||
$crate::Piece::new($crate::Color::$color, $crate::Shape::$shape)
|
||||
};
|
||||
($color:ident $shape:ident on $square:ident) => {
|
||||
$crate::PlacedPiece::new(piece!($color $shape), $crate::Square::$square)
|
||||
}
|
||||
}
|
255
core/src/pieces.rs
Normal file
255
core/src/pieces.rs
Normal file
|
@ -0,0 +1,255 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{errors::TryFromCharError, try_from_string, Color, Square};
|
||||
use std::{fmt, slice::Iter};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Shape {
|
||||
Pawn = 0,
|
||||
Knight = 1,
|
||||
Bishop = 2,
|
||||
Rook = 3,
|
||||
Queen = 4,
|
||||
King = 5,
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
pub fn iter() -> Iter<'static, Shape> {
|
||||
const ALL_SHAPES: [Shape; 6] = [
|
||||
Shape::Pawn,
|
||||
Shape::Knight,
|
||||
Shape::Bishop,
|
||||
Shape::Rook,
|
||||
Shape::Queen,
|
||||
Shape::King,
|
||||
];
|
||||
|
||||
ALL_SHAPES.iter()
|
||||
}
|
||||
|
||||
pub fn promotable() -> Iter<'static, Shape> {
|
||||
const PROMOTABLE_SHAPES: [Shape; 4] =
|
||||
[Shape::Queen, Shape::Rook, Shape::Bishop, Shape::Knight];
|
||||
|
||||
PROMOTABLE_SHAPES.iter()
|
||||
}
|
||||
|
||||
fn to_ascii(&self) -> char {
|
||||
match self {
|
||||
Shape::Pawn => 'P',
|
||||
Shape::Knight => 'N',
|
||||
Shape::Bishop => 'B',
|
||||
Shape::Rook => 'R',
|
||||
Shape::Queen => 'Q',
|
||||
Shape::King => 'K',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<char> for Shape {
|
||||
type Error = TryFromCharError;
|
||||
|
||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
'P' | 'p' => Ok(Shape::Pawn),
|
||||
'N' | 'n' => Ok(Shape::Knight),
|
||||
'B' | 'b' => Ok(Shape::Bishop),
|
||||
'R' | 'r' => Ok(Shape::Rook),
|
||||
'Q' | 'q' => Ok(Shape::Queen),
|
||||
'K' | 'k' => Ok(Shape::King),
|
||||
_ => Err(TryFromCharError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try_from_string!(Shape);
|
||||
|
||||
impl Into<char> for &Shape {
|
||||
fn into(self) -> char {
|
||||
self.to_ascii()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<char> for Shape {
|
||||
fn into(self) -> char {
|
||||
self.to_ascii()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Shape {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let self_char: char = self.into();
|
||||
write!(f, "{}", self_char)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Piece {
|
||||
color: Color,
|
||||
shape: Shape,
|
||||
}
|
||||
|
||||
macro_rules! piece_constructor {
|
||||
($func_name:ident, $type:tt) => {
|
||||
pub fn $func_name(color: Color) -> Piece {
|
||||
Piece {
|
||||
color,
|
||||
shape: Shape::$type,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_shape {
|
||||
($func_name:ident, $shape:ident) => {
|
||||
pub fn $func_name(&self) -> bool {
|
||||
self.shape == Shape::$shape
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Piece {
|
||||
pub fn new(color: Color, shape: Shape) -> Piece {
|
||||
Piece { color, shape }
|
||||
}
|
||||
|
||||
piece_constructor!(pawn, Pawn);
|
||||
piece_constructor!(knight, Knight);
|
||||
piece_constructor!(bishop, Bishop);
|
||||
piece_constructor!(rook, Rook);
|
||||
piece_constructor!(queen, Queen);
|
||||
piece_constructor!(king, King);
|
||||
|
||||
pub fn color(&self) -> Color {
|
||||
self.color
|
||||
}
|
||||
|
||||
pub fn shape(&self) -> Shape {
|
||||
self.shape
|
||||
}
|
||||
|
||||
is_shape!(is_pawn, Pawn);
|
||||
is_shape!(is_knight, Knight);
|
||||
is_shape!(is_bishop, Bishop);
|
||||
is_shape!(is_rook, Rook);
|
||||
is_shape!(is_queen, Queen);
|
||||
is_shape!(is_king, King);
|
||||
|
||||
pub fn to_ascii(&self) -> char {
|
||||
self.shape.to_ascii()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Piece {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match (self.color, self.shape) {
|
||||
(Color::Black, Shape::Pawn) => '♟',
|
||||
(Color::Black, Shape::Knight) => '♞',
|
||||
(Color::Black, Shape::Bishop) => '♝',
|
||||
(Color::Black, Shape::Rook) => '♜',
|
||||
(Color::Black, Shape::Queen) => '♛',
|
||||
(Color::Black, Shape::King) => '♚',
|
||||
(Color::White, Shape::Pawn) => '♙',
|
||||
(Color::White, Shape::Knight) => '♘',
|
||||
(Color::White, Shape::Bishop) => '♗',
|
||||
(Color::White, Shape::Rook) => '♖',
|
||||
(Color::White, Shape::Queen) => '♕',
|
||||
(Color::White, Shape::King) => '♔',
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PlacedPiece {
|
||||
piece: Piece,
|
||||
square: Square,
|
||||
}
|
||||
|
||||
macro_rules! is_shape {
|
||||
($func_name:ident, $shape:ident) => {
|
||||
pub fn $func_name(&self) -> bool {
|
||||
self.piece().shape == Shape::$shape
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl PlacedPiece {
|
||||
pub const fn new(piece: Piece, square: Square) -> PlacedPiece {
|
||||
PlacedPiece { piece, square }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn piece(&self) -> &Piece {
|
||||
&self.piece
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn square(&self) -> Square {
|
||||
self.square
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn color(&self) -> Color {
|
||||
self.piece.color
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shape(&self) -> Shape {
|
||||
self.piece.shape
|
||||
}
|
||||
|
||||
is_shape!(is_pawn, Pawn);
|
||||
is_shape!(is_knight, Knight);
|
||||
is_shape!(is_bishop, Bishop);
|
||||
is_shape!(is_rook, Rook);
|
||||
is_shape!(is_queen, Queen);
|
||||
is_shape!(is_king, King);
|
||||
|
||||
pub fn is_kingside_rook(&self) -> bool {
|
||||
self.is_rook()
|
||||
&& match self.color() {
|
||||
Color::White => self.square == Square::H1,
|
||||
Color::Black => self.square == Square::H8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_queenside_rook(&self) -> bool {
|
||||
self.is_rook()
|
||||
&& match self.color() {
|
||||
Color::White => self.square == Square::A1,
|
||||
Color::Black => self.square == Square::A8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PlacedPiece {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{}", self.piece, self.square)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&Square, &Piece)> for PlacedPiece {
|
||||
fn from(value: (&Square, &Piece)) -> Self {
|
||||
PlacedPiece::new(*value.1, *value.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn shape_try_from() {
|
||||
assert_eq!(Shape::try_from('p'), Ok(Shape::Pawn));
|
||||
assert_eq!(Shape::try_from("p"), Ok(Shape::Pawn));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shape_into_char() {
|
||||
assert_eq!(<Shape as Into<char>>::into(Shape::Pawn) as char, 'P');
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue