diff --git a/Cargo.lock b/Cargo.lock index e49153a..3ebe93a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,6 +121,10 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "core" +version = "0.1.0" + [[package]] name = "endian-type" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index d595fa5..cfa9c81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "board", + "bitboard", "core", "explorer", ] diff --git a/bitboard/Cargo.toml b/bitboard/Cargo.toml new file mode 100644 index 0000000..df608b5 --- /dev/null +++ b/bitboard/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "chessfriend_bitboard" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chessfriend_core = { path = "../core" } diff --git a/board/src/bitboard/bit_scanner.rs b/bitboard/src/bit_scanner.rs similarity index 100% rename from board/src/bitboard/bit_scanner.rs rename to bitboard/src/bit_scanner.rs diff --git a/board/src/bitboard/bitboard.rs b/bitboard/src/bitboard.rs similarity index 94% rename from board/src/bitboard/bitboard.rs rename to bitboard/src/bitboard.rs index 5c35ca8..6aa0df2 100644 --- a/board/src/bitboard/bitboard.rs +++ b/bitboard/src/bitboard.rs @@ -1,13 +1,13 @@ // Eryn Wells -use super::library::{library, FILES, RANKS}; -use super::LeadingBitScanner; -use crate::{square::Direction, Square}; +use crate::library::{library, FILES, RANKS}; +use crate::LeadingBitScanner; +use chessfriend_core::{Direction, Square}; use std::fmt; use std::ops::Not; #[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub(crate) struct BitBoard(pub(super) u64); +pub struct BitBoard(pub(crate) u64); macro_rules! moves_getter { ($getter_name:ident) => { @@ -71,14 +71,14 @@ impl BitBoard { impl BitBoard { /// Return an Iterator over the occupied squares, starting from the leading /// (most-significant bit) end of the field. - pub(crate) fn occupied_squares(&self) -> impl Iterator { - LeadingBitScanner::new(self.0).map(Square::from_index) + pub fn occupied_squares(&self) -> impl Iterator { + LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index(idx as u8) }) } /// Return an Iterator over the occupied squares, starting from the trailing /// (least-significant bit) end of the field. - pub(crate) fn occupied_squares_trailing(&self) -> impl Iterator { - LeadingBitScanner::new(self.0).map(Square::from_index) + pub fn occupied_squares_trailing(&self) -> impl Iterator { + LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index(idx as u8) }) } } @@ -243,7 +243,8 @@ impl BitBoardBuilder { #[cfg(test)] mod tests { use super::*; - use crate::{bitboard, Square}; + use crate::bitboard; + use chessfriend_core::Square; #[test] fn display_and_debug() { diff --git a/board/src/bitboard/mod.rs b/bitboard/src/lib.rs similarity index 56% rename from board/src/bitboard/mod.rs rename to bitboard/src/lib.rs index c417abd..30a35f2 100644 --- a/board/src/bitboard/mod.rs +++ b/bitboard/src/lib.rs @@ -1,16 +1,19 @@ +// Eryn Wells + mod bit_scanner; mod bitboard; mod library; mod shifts; +pub use bitboard::{BitBoard, BitBoardBuilder}; + pub(crate) use bit_scanner::{LeadingBitScanner, TrailingBitScanner}; -pub(crate) use bitboard::{BitBoard, BitBoardBuilder}; #[macro_export] macro_rules! bitboard { ($($sq:ident),* $(,)?) => { - $crate::bitboard::BitBoardBuilder::empty() - $(.square($crate::Square::$sq))* + $crate::BitBoardBuilder::empty() + $(.square(chessfriend_core::Square::$sq))* .build() }; } diff --git a/board/src/bitboard/library.rs b/bitboard/src/library.rs similarity index 98% rename from board/src/bitboard/library.rs rename to bitboard/src/library.rs index fe2daa0..6c59291 100644 --- a/board/src/bitboard/library.rs +++ b/bitboard/src/library.rs @@ -1,7 +1,7 @@ // Eryn Wells -use super::BitBoard; -use crate::{square::Direction, Square}; +use crate::BitBoard; +use chessfriend_core::{Direction, Square}; use std::sync::Once; pub(super) const RANKS: [BitBoard; 8] = [ diff --git a/board/src/bitboard/shifts.rs b/bitboard/src/shifts.rs similarity index 100% rename from board/src/bitboard/shifts.rs rename to bitboard/src/shifts.rs diff --git a/board/Cargo.toml b/board/Cargo.toml index 6b600a9..70584c2 100644 --- a/board/Cargo.toml +++ b/board/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chessfriend_core = { path = "../core" } +chessfriend_bitboard = { path = "../bitboard" } diff --git a/board/src/fen.rs b/board/src/fen.rs index b212c94..8610f00 100644 --- a/board/src/fen.rs +++ b/board/src/fen.rs @@ -3,8 +3,9 @@ use crate::{ piece::{Piece, PlacedPiece}, r#move::Castle, - Color, File, Position, Rank, Square, + Color, Position, }; +use chessfriend_core::{File, Rank, Square}; use std::fmt::Write; #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -42,7 +43,7 @@ impl ToFen for Position { write!(fen_string, "{}", empty_squares).map_err(|err| FenError::FmtError(err))?; empty_squares = 0; } - if rank != &Rank::One { + if rank != &Rank::ONE { write!(fen_string, "/").map_err(|err| FenError::FmtError(err))?; } } diff --git a/board/src/lib.rs b/board/src/lib.rs index 3db0753..243686e 100644 --- a/board/src/lib.rs +++ b/board/src/lib.rs @@ -2,8 +2,6 @@ pub mod fen; -#[macro_use] -mod bitboard; mod display; mod r#move; #[macro_use] @@ -12,11 +10,7 @@ mod move_generator; pub mod piece; mod position; mod sight; -mod square; pub use piece::{Color, Piece}; pub use position::{MoveBuilder as MakeMoveBuilder, Position, PositionBuilder}; pub use r#move::{Castle, MakeMoveError, Move, MoveBuilder}; -pub use square::{File, Rank, Square}; - -pub(crate) use bitboard::BitBoard; diff --git a/board/src/macros.rs b/board/src/macros.rs index 9dd3323..c6c374c 100644 --- a/board/src/macros.rs +++ b/board/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! piece { $crate::piece::Piece::new($crate::piece::Color::$color, $crate::piece::Shape::$shape) }; ($color:ident $shape:ident on $square:ident) => { - $crate::piece::PlacedPiece::new(piece!($color $shape), $crate::square::Square::$square) + $crate::piece::PlacedPiece::new(piece!($color $shape), chessfriend_core::Square::$square) } } diff --git a/board/src/move.rs b/board/src/move.rs index 08cf988..7b3e55c 100644 --- a/board/src/move.rs +++ b/board/src/move.rs @@ -1,10 +1,7 @@ // Eryn Wells -use crate::{ - piece::{Piece, PlacedPiece, Shape}, - square::Rank, - Square, -}; +use crate::piece::{Piece, PlacedPiece, Shape}; +use chessfriend_core::{Rank, Square}; use std::fmt; pub use castle::Castle; @@ -20,7 +17,8 @@ pub enum MakeMoveError { } mod castle { - use crate::{Color, Square}; + use crate::Color; + use chessfriend_core::Square; #[repr(u16)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -248,8 +246,8 @@ impl MoveBuilder { Shape::Pawn => { let from_rank = from.rank(); let to_rank = to.rank(); - let is_white_double_push = from_rank == Rank::Two && to_rank == Rank::Four; - let is_black_double_push = from_rank == Rank::Seven && to_rank == Rank::Five; + let is_white_double_push = from_rank == Rank::TWO && to_rank == Rank::FOUR; + let is_black_double_push = from_rank == Rank::SEVEN && to_rank == Rank::FIVE; if is_white_double_push || is_black_double_push { Kind::DoublePush } else { @@ -421,8 +419,8 @@ mod move_formatter { $crate::piece::Color::$color, $crate::piece::Shape::$shape, ), - $crate::Square::$from_square, - $crate::Square::$to_square, + chessfriend_core::Square::$from_square, + chessfriend_core::Square::$to_square, ) .build() }; @@ -432,15 +430,15 @@ mod move_formatter { $crate::piece::Color::$color, $crate::piece::Shape::$shape, ), - $crate::Square::$from_square, - $crate::Square::$to_square, + chessfriend_core::Square::$from_square, + chessfriend_core::Square::$to_square, ) .capturing($crate::piece::PlacedPiece::new( $crate::piece::Piece::new( $crate::piece::Color::$captured_color, $crate::piece::Shape::$captured_shape, ), - $crate::Square::$to_square, + chessfriend_core::Square::$to_square, )) .build() }; diff --git a/board/src/move_generator/bishop.rs b/board/src/move_generator/bishop.rs index 7b07d54..404d68b 100644 --- a/board/src/move_generator/bishop.rs +++ b/board/src/move_generator/bishop.rs @@ -3,9 +3,10 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, - square::Direction, - BitBoard, MoveBuilder, Position, + MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Direction; move_generator_declaration!(ClassicalMoveGenerator); @@ -60,7 +61,8 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::{piece, piece::Color, position, position::DiagramFormatter, BitBoard}; + use crate::{piece, piece::Color, position, position::DiagramFormatter}; + use chessfriend_bitboard::BitBoard; #[test] fn classical_single_bishop_bitboard() { diff --git a/board/src/move_generator/king.rs b/board/src/move_generator/king.rs index 06ae76e..643a987 100644 --- a/board/src/move_generator/king.rs +++ b/board/src/move_generator/king.rs @@ -7,8 +7,9 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, r#move::Castle, - BitBoard, Move, MoveBuilder, Position, + Move, MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; move_generator_declaration!(KingMoveGenerator, struct); move_generator_declaration!(KingMoveGenerator, new); @@ -76,7 +77,8 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::Square; + use chessfriend_bitboard::bitboard; + use chessfriend_core::Square; use std::collections::HashSet; #[test] diff --git a/board/src/move_generator/knight.rs b/board/src/move_generator/knight.rs index 50a7ad0..64b360f 100644 --- a/board/src/move_generator/knight.rs +++ b/board/src/move_generator/knight.rs @@ -3,8 +3,9 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, - BitBoard, MoveBuilder, Position, + MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; move_generator_declaration!(KnightMoveGenerator); @@ -40,7 +41,8 @@ impl<'pos> MoveGeneratorInternal for KnightMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::{piece, position, Move, Square}; + use crate::{piece, position, Move}; + use chessfriend_core::Square; use std::collections::HashSet; #[test] diff --git a/board/src/move_generator/mod.rs b/board/src/move_generator/mod.rs index eb080c3..ed5ac74 100644 --- a/board/src/move_generator/mod.rs +++ b/board/src/move_generator/mod.rs @@ -14,8 +14,9 @@ pub(crate) use move_set::MoveSet; use crate::{ piece::{Color, Piece, PlacedPiece}, - Move, Position, Square, + Move, Position, }; +use chessfriend_core::Square; use std::collections::BTreeMap; trait MoveGenerator { @@ -34,7 +35,10 @@ macro_rules! move_generator_declaration { pub(super) struct $name<'pos> { position: &'pos $crate::Position, color: $crate::piece::Color, - move_sets: std::collections::BTreeMap<$crate::Square, $crate::move_generator::MoveSet>, + move_sets: std::collections::BTreeMap< + chessfriend_core::Square, + $crate::move_generator::MoveSet, + >, } }; ($name:ident, new) => { @@ -54,12 +58,11 @@ macro_rules! move_generator_declaration { self.move_sets.values().map(|set| set.moves()).flatten() } - fn bitboard(&self) -> $crate::BitBoard { - self.move_sets - .values() - .fold($crate::BitBoard::empty(), |partial, mv_set| { - partial | mv_set.bitboard() - }) + fn bitboard(&self) -> chessfriend_bitboard::BitBoard { + self.move_sets.values().fold( + chessfriend_bitboard::BitBoard::empty(), + |partial, mv_set| partial | mv_set.bitboard(), + ) } } }; diff --git a/board/src/move_generator/move_generator.rs b/board/src/move_generator/move_generator.rs index 689e47d..2ef4922 100644 --- a/board/src/move_generator/move_generator.rs +++ b/board/src/move_generator/move_generator.rs @@ -43,7 +43,8 @@ impl<'a> Moves<'a> { #[cfg(test)] mod tests { - use crate::{piece, position, r#move::AlgebraicMoveFormatter, Move, MoveBuilder, Square}; + use crate::{piece, position, r#move::AlgebraicMoveFormatter, Move, MoveBuilder}; + use chessfriend_core::Square; use std::collections::HashSet; #[test] diff --git a/board/src/move_generator/move_set.rs b/board/src/move_generator/move_set.rs index 1c44766..1c22eac 100644 --- a/board/src/move_generator/move_set.rs +++ b/board/src/move_generator/move_set.rs @@ -1,4 +1,5 @@ -use crate::{piece::PlacedPiece, BitBoard, Move}; +use crate::{piece::PlacedPiece, Move}; +use chessfriend_bitboard::BitBoard; #[derive(Clone, Debug, Eq, PartialEq)] struct BitBoardSet { diff --git a/board/src/move_generator/pawn.rs b/board/src/move_generator/pawn.rs index 7f77e15..d366405 100644 --- a/board/src/move_generator/pawn.rs +++ b/board/src/move_generator/pawn.rs @@ -2,8 +2,9 @@ use crate::{ piece::{Color, Piece, Shape}, - BitBoard, Move, MoveBuilder, Position, + Move, MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; enum MoveList { Quiet = 0, @@ -246,7 +247,8 @@ impl<'pos> Iterator for PawnMoveGenerator<'pos> { mod tests { use super::*; use crate::position::DiagramFormatter; - use crate::{piece, Position, Square}; + use crate::{piece, Position}; + use chessfriend_core::Square; use std::collections::HashSet; #[test] diff --git a/board/src/move_generator/queen.rs b/board/src/move_generator/queen.rs index 6694bf6..fb96dd7 100644 --- a/board/src/move_generator/queen.rs +++ b/board/src/move_generator/queen.rs @@ -3,9 +3,10 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, - square::Direction, - BitBoard, MoveBuilder, Position, + MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Direction; move_generator_declaration!(ClassicalMoveGenerator); @@ -66,7 +67,8 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::{piece, position, position::DiagramFormatter, BitBoard, Color}; + use crate::{piece, position, position::DiagramFormatter, Color}; + use chessfriend_bitboard::{bitboard, BitBoard}; #[test] fn classical_single_queen_bitboard() { diff --git a/board/src/move_generator/rook.rs b/board/src/move_generator/rook.rs index bd48711..570255a 100644 --- a/board/src/move_generator/rook.rs +++ b/board/src/move_generator/rook.rs @@ -3,9 +3,10 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, - square::Direction, - BitBoard, MoveBuilder, Position, + MoveBuilder, Position, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Direction; move_generator_declaration!(ClassicalMoveGenerator); @@ -62,9 +63,9 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::{ - piece::Piece, position, position::DiagramFormatter, BitBoard, Color, Position, Square, - }; + use crate::{piece::Piece, position, position::DiagramFormatter, Color, Position}; + use chessfriend_bitboard::{bitboard, BitBoard}; + use chessfriend_core::Square; #[test] fn classical_single_rook_bitboard() { diff --git a/board/src/piece.rs b/board/src/piece.rs index f65a7b8..b80d1da 100644 --- a/board/src/piece.rs +++ b/board/src/piece.rs @@ -1,9 +1,7 @@ // Eryn Wells -use crate::{ - display::{ASCIIDisplay, FENDisplay, UnicodeDisplay}, - Square, -}; +use crate::display::{ASCIIDisplay, FENDisplay, UnicodeDisplay}; +use chessfriend_core::Square; use std::fmt; use std::slice::Iter; diff --git a/board/src/position/builders/move_builder.rs b/board/src/position/builders/move_builder.rs index 5d12b19..4530543 100644 --- a/board/src/position/builders/move_builder.rs +++ b/board/src/position/builders/move_builder.rs @@ -4,9 +4,10 @@ use crate::{ piece::{PlacedPiece, Shape}, position::flags::Flags, r#move::Castle, - square::Direction, - BitBoard, Color, MakeMoveError, Move, Piece, Position, Square, + Color, MakeMoveError, Move, Piece, Position, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::{Direction, Square}; /// A position builder that builds a new position by making a move. #[derive(Clone)] diff --git a/board/src/position/builders/position_builder.rs b/board/src/position/builders/position_builder.rs index 7c68413..88838b7 100644 --- a/board/src/position/builders/position_builder.rs +++ b/board/src/position/builders/position_builder.rs @@ -1,13 +1,12 @@ // Eryn Wells use crate::{ - bitboard::BitBoardBuilder, piece::{PlacedPiece, Shape}, position::{flags::Flags, piece_sets::PieceBitBoards}, r#move::Castle, - square::{Direction, Rank}, - BitBoard, Color, MakeMoveError, Move, Piece, Position, Square, + Color, MakeMoveError, Move, Piece, Position, }; +use chessfriend_core::{Rank, Square}; use std::collections::BTreeMap; #[derive(Clone)] @@ -100,7 +99,7 @@ impl Builder { // Pawns cannot be placed on the first (back) rank of their side, // and cannot be placed on the final rank without a promotion. let rank = piece.square().rank(); - return rank != Rank::One && rank != Rank::Eight; + return rank != Rank::ONE && rank != Rank::EIGHT; } true @@ -109,8 +108,8 @@ impl Builder { impl Default for Builder { fn default() -> Self { - let white_king_square = Square::king_starting_square(Color::White); - let black_king_square = Square::king_starting_square(Color::Black); + let white_king_square = Square::E1; + let black_king_square = Square::E8; let pieces = BTreeMap::from_iter([ (white_king_square, piece!(White King)), diff --git a/board/src/position/diagram_formatter.rs b/board/src/position/diagram_formatter.rs index b007d20..0c46de4 100644 --- a/board/src/position/diagram_formatter.rs +++ b/board/src/position/diagram_formatter.rs @@ -1,6 +1,7 @@ // Eryn Wells -use crate::{File, Position, Rank, Square}; +use crate::Position; +use chessfriend_core::{File, Rank, Square}; use std::fmt; pub struct DiagramFormatter<'a>(&'a Position); diff --git a/board/src/position/piece_sets.rs b/board/src/position/piece_sets.rs index 58921b9..d07eb2a 100644 --- a/board/src/position/piece_sets.rs +++ b/board/src/position/piece_sets.rs @@ -2,8 +2,10 @@ use crate::{ piece::{Piece, PlacedPiece}, - BitBoard, Color, Square, + Color, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Square; #[derive(Debug, Eq, PartialEq)] pub enum PlacePieceStrategy { @@ -124,7 +126,7 @@ impl PieceBitBoards { impl FromIterator for PieceBitBoards { fn from_iter>(iter: T) -> Self { - let mut pieces = Self::default(); + let mut pieces: Self = Default::default(); for piece in iter { let _ = pieces.place_piece(&piece); diff --git a/board/src/position/pieces.rs b/board/src/position/pieces.rs index d1cb6c7..8530869 100644 --- a/board/src/position/pieces.rs +++ b/board/src/position/pieces.rs @@ -2,8 +2,8 @@ use super::Position; use crate::piece::{Color, Piece, PlacedPiece, Shape}; -use crate::BitBoard; -use crate::Square; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Square; pub struct Pieces<'a> { color: Color, @@ -76,7 +76,6 @@ impl<'a> Iterator for Pieces<'a> { mod tests { use super::*; use crate::piece::{Color, Piece, Shape}; - use crate::Square; use crate::{Position, PositionBuilder}; use std::collections::HashSet; diff --git a/board/src/position/position.rs b/board/src/position/position.rs index 484293e..82ef1bd 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -7,8 +7,10 @@ use crate::{ position::DiagramFormatter, r#move::Castle, sight::Sight, - BitBoard, Move, Square, + Move, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Square; use std::{cell::OnceCell, fmt}; #[derive(Clone, Debug, Eq, PartialEq)] @@ -266,7 +268,8 @@ impl fmt::Display for Position { #[cfg(test)] mod tests { - use crate::{position, Castle, Color, Position, Square}; + use crate::{position, Castle, Color, Position}; + use chessfriend_core::Square; #[test] fn piece_on_square() { diff --git a/board/src/sight.rs b/board/src/sight.rs index 33bd2d8..ffed3f7 100644 --- a/board/src/sight.rs +++ b/board/src/sight.rs @@ -2,9 +2,10 @@ use crate::{ piece::{Color, PlacedPiece, Shape}, - square::Direction, - BitBoard, Position, + Position, }; +use chessfriend_bitboard::BitBoard; +use chessfriend_core::Direction; pub(crate) trait Sight { fn sight_in_position(&self, position: &Position) -> BitBoard; @@ -174,7 +175,9 @@ mod tests { } mod pawn { - use crate::{sight::Sight, BitBoard, Square}; + use crate::sight::Sight; + use chessfriend_bitboard::{bitboard, BitBoard}; + use chessfriend_core::Square; sight_test!(e4_pawn, piece!(White Pawn on E4), bitboard!(D5, F5)); @@ -233,6 +236,7 @@ mod tests { #[macro_use] mod knight { use crate::sight::Sight; + use chessfriend_bitboard::bitboard; sight_test!( f6_knight, @@ -243,6 +247,7 @@ mod tests { mod bishop { use crate::sight::Sight; + use chessfriend_bitboard::bitboard; sight_test!( c2_bishop, @@ -253,6 +258,7 @@ mod tests { mod rook { use crate::sight::Sight; + use chessfriend_bitboard::bitboard; sight_test!( g3_rook, diff --git a/board/src/square.rs b/board/src/square.rs deleted file mode 100644 index 23565cf..0000000 --- a/board/src/square.rs +++ /dev/null @@ -1,360 +0,0 @@ -// Eryn Wells - -use crate::Color; -use std::{fmt, str::FromStr}; - -pub enum Direction { - North, - NorthWest, - West, - SouthWest, - South, - SouthEast, - East, - NorthEast, -} - -#[derive(Debug)] -pub struct ParseFileError; - -#[derive(Debug)] -pub struct ParseSquareError; - -#[derive(Debug)] -pub struct SquareOutOfBoundsError; - -macro_rules! coordinate_enum { - ($name: ident, $($variant:ident),*) => { - #[repr(u8)] - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - pub enum $name { - $($variant), * - } - - impl $name { - pub const NUM: usize = [$(Self::$variant), *].len(); - pub const ALL: [Self; Self::NUM] = [$(Self::$variant), *]; - - #[inline] - pub(crate) fn from_index(index: usize) -> Self { - assert!( - index < Self::NUM, - "Index {} out of bounds for {}.", - index, - stringify!($name) - ); - Self::try_index(index).unwrap() - } - - pub fn try_index(index: usize) -> Option { - $( - #[allow(non_upper_case_globals)] - const $variant: usize = $name::$variant as usize; - )* - - #[allow(non_upper_case_globals)] - match index { - $($variant => Some($name::$variant),)* - _ => None, - } - } - } - } -} - -#[rustfmt::skip] -coordinate_enum!(Rank, - One, Two, Three, Four, Five, Six, Seven, Eight -); - -#[rustfmt::skip] -coordinate_enum!(File, - A, B, C, D, E, F, G, H -); - -#[rustfmt::skip] -coordinate_enum!(Square, - A1, B1, C1, D1, E1, F1, G1, H1, - A2, B2, C2, D2, E2, F2, G2, H2, - A3, B3, C3, D3, E3, F3, G3, H3, - A4, B4, C4, D4, E4, F4, G4, H4, - A5, B5, C5, D5, E5, F5, G5, H5, - A6, B6, C6, D6, E6, F6, G6, H6, - A7, B7, C7, D7, E7, F7, G7, H7, - A8, B8, C8, D8, E8, F8, G8, H8 -); - -impl Into for File { - fn into(self) -> char { - ('a' as u8 + self as u8) as char - } -} - -impl TryFrom for File { - type Error = ParseFileError; - - fn try_from(value: char) -> Result { - let lowercase_value = value.to_ascii_lowercase(); - for file in File::ALL.iter() { - if lowercase_value == (*file).into() { - return Ok(*file); - } - } - - Err(ParseFileError) - } -} - -impl fmt::Display for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", Into::::into(*self).to_uppercase()) - } -} - -impl Into for Rank { - fn into(self) -> char { - ('1' as u8 + self as u8) as char - } -} - -impl TryFrom for Rank { - type Error = ParseFileError; - - fn try_from(value: char) -> Result { - let lowercase_value = value.to_ascii_lowercase(); - for rank in Self::ALL.iter().cloned() { - if lowercase_value == rank.into() { - return Ok(rank); - } - } - - Err(ParseFileError) - } -} - -impl fmt::Display for Rank { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", Into::::into(*self)) - } -} - -impl Square { - #[inline] - pub fn from_file_rank(file: File, rank: Rank) -> Square { - Self::from_index((rank as usize) << 3 | file as usize) - } - - #[inline] - pub fn file(self) -> File { - File::from_index(self as usize & 0b000111) - } - - #[inline] - pub fn rank(self) -> Rank { - Rank::from_index(self as usize >> 3) - } -} - -impl Square { - const KING_STARTING_SQUARES: [Square; 2] = [Square::E1, Square::E8]; - - pub fn king_starting_square(color: Color) -> Square { - Square::KING_STARTING_SQUARES[color as usize] - } - - pub fn from_algebraic_str(s: &str) -> Result { - s.parse() - } - - pub fn neighbor(self, direction: Direction) -> Option { - match direction { - Direction::North => Square::try_index(self as usize + 8), - Direction::NorthWest => { - if self.rank() != Rank::Eight { - Square::try_index(self as usize + 7) - } else { - None - } - } - Direction::West => { - if self.file() != File::A { - Square::try_index(self as usize - 1) - } else { - None - } - } - Direction::SouthWest => { - if self.rank() != Rank::One { - Square::try_index(self as usize - 9) - } else { - None - } - } - Direction::South => { - if self.rank() != Rank::One { - Square::try_index(self as usize - 8) - } else { - None - } - } - Direction::SouthEast => { - if self.rank() != Rank::One { - Square::try_index(self as usize - 7) - } else { - None - } - } - Direction::East => { - if self.file() != File::H { - Square::try_index(self as usize + 1) - } else { - None - } - } - Direction::NorthEast => Square::try_index(self as usize + 9), - } - } -} - -impl FromStr for Square { - type Err = ParseSquareError; - - fn from_str(s: &str) -> Result { - let mut chars = s.chars(); - - let file: File = chars - .next() - .and_then(|c| c.try_into().ok()) - .ok_or(ParseSquareError)?; - - let rank: Rank = chars - .next() - .and_then(|c| c.try_into().ok()) - .ok_or(ParseSquareError)?; - - if !chars.next().is_none() { - return Err(ParseSquareError); - } - - Ok(Square::from_file_rank(file, rank)) - } -} - -macro_rules! try_from_integer { - ($int_type:ident) => { - impl TryFrom<$int_type> for Square { - type Error = SquareOutOfBoundsError; - - fn try_from(value: $int_type) -> Result { - Square::try_index(value as usize).ok_or(SquareOutOfBoundsError) - } - } - }; -} - -try_from_integer!(u8); -try_from_integer!(u16); -try_from_integer!(u32); -try_from_integer!(u64); - -impl fmt::Display for Square { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}{}", - ('a' as u8 + self.file() as u8) as char, - self.rank() as usize + 1 - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn good_algebraic_input() { - let sq = Square::from_algebraic_str("a4").expect("Failed to parse 'a4' square"); - assert_eq!(sq.file(), File::A); - assert_eq!(sq.rank(), Rank::Four); - - let sq = Square::from_algebraic_str("B8").expect("Failed to parse 'B8' square"); - assert_eq!(sq.file(), File::B); - assert_eq!(sq.rank(), Rank::Eight); - - let sq = Square::from_algebraic_str("e4").expect("Failed to parse 'B8' square"); - assert_eq!(sq.file(), File::E); - assert_eq!(sq.rank(), Rank::Four); - } - - #[test] - fn bad_algebraic_input() { - Square::from_algebraic_str("a0").expect_err("Got valid Square for 'a0'"); - Square::from_algebraic_str("j3").expect_err("Got valid Square for 'j3'"); - Square::from_algebraic_str("a11").expect_err("Got valid Square for 'a11'"); - Square::from_algebraic_str("b-1").expect_err("Got valid Square for 'b-1'"); - Square::from_algebraic_str("a 1").expect_err("Got valid Square for 'a 1'"); - Square::from_algebraic_str("").expect_err("Got valid Square for ''"); - } - - #[test] - fn from_index() { - let sq = Square::try_index(4).expect("Unable to get Square from index"); - assert_eq!(sq.file(), File::E); - assert_eq!(sq.rank(), Rank::One); - - let sq = Square::try_index(28).expect("Unable to get Square from index"); - assert_eq!(sq.file(), File::E); - assert_eq!(sq.rank(), Rank::Four); - } - - #[test] - fn to_index() { - assert_eq!(Square::A1 as usize, 0); - assert_eq!(Square::H8 as usize, 63); - } - - #[test] - fn valid_neighbors() { - let sq = Square::E4; - - assert_eq!(sq.neighbor(Direction::North), Some(Square::E5)); - assert_eq!(sq.neighbor(Direction::NorthEast), Some(Square::F5)); - assert_eq!(sq.neighbor(Direction::East), Some(Square::F4)); - assert_eq!(sq.neighbor(Direction::SouthEast), Some(Square::F3)); - assert_eq!(sq.neighbor(Direction::South), Some(Square::E3)); - assert_eq!(sq.neighbor(Direction::SouthWest), Some(Square::D3)); - assert_eq!(sq.neighbor(Direction::West), Some(Square::D4)); - assert_eq!(sq.neighbor(Direction::NorthWest), Some(Square::D5)); - } - - #[test] - fn invalid_neighbors() { - let sq = Square::A1; - assert!(sq.neighbor(Direction::West).is_none()); - assert!(sq.neighbor(Direction::SouthWest).is_none()); - assert!(sq.neighbor(Direction::South).is_none()); - - let sq = Square::H1; - assert!(sq.neighbor(Direction::East).is_none()); - assert!(sq.neighbor(Direction::SouthEast).is_none()); - assert!(sq.neighbor(Direction::South).is_none()); - - let sq = Square::A8; - assert!(sq.neighbor(Direction::North).is_none()); - assert!(sq.neighbor(Direction::NorthWest).is_none()); - assert!(sq.neighbor(Direction::West).is_none()); - - let sq = Square::H8; - assert!(sq.neighbor(Direction::North).is_none()); - assert!(sq.neighbor(Direction::NorthEast).is_none()); - assert!(sq.neighbor(Direction::East).is_none()); - } - - #[test] - fn display() { - assert_eq!(format!("{}", Square::C5), "c5"); - assert_eq!(format!("{}", Square::A1), "a1"); - assert_eq!(format!("{}", Square::H8), "h8"); - } -} diff --git a/core/Cargo.toml b/core/Cargo.toml index 900733d..9b33128 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "core" +name = "chessfriend_core" version = "0.1.0" edition = "2021" diff --git a/explorer/Cargo.toml b/explorer/Cargo.toml index 5d49281..3f2513b 100644 --- a/explorer/Cargo.toml +++ b/explorer/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chessfriend_core = { path = "../core" } board = { path = "../board" } clap = { version = "4.4.12", features = ["derive"] } rustyline = "13.0.0" diff --git a/explorer/src/main.rs b/explorer/src/main.rs index 9da6a64..e8fca2f 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -1,5 +1,6 @@ use board::piece::{Color, Piece, Shape}; -use board::{Position, Square}; +use board::Position; +use chessfriend_core::Square; use clap::{Arg, Command}; use rustyline::error::ReadlineError; use rustyline::DefaultEditor;