Merge branch 'many-crates'
# Conflicts: # Cargo.toml # core/Cargo.toml
This commit is contained in:
commit
3c71687838
34 changed files with 128 additions and 448 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -121,6 +121,10 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endian-type"
|
name = "endian-type"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"board",
|
"board",
|
||||||
|
"bitboard",
|
||||||
"core",
|
"core",
|
||||||
"explorer",
|
"explorer",
|
||||||
]
|
]
|
||||||
|
|
9
bitboard/Cargo.toml
Normal file
9
bitboard/Cargo.toml
Normal file
|
@ -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" }
|
|
@ -1,13 +1,13 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::library::{library, FILES, RANKS};
|
use crate::library::{library, FILES, RANKS};
|
||||||
use super::LeadingBitScanner;
|
use crate::LeadingBitScanner;
|
||||||
use crate::{square::Direction, Square};
|
use chessfriend_core::{Direction, Square};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
pub(crate) struct BitBoard(pub(super) u64);
|
pub struct BitBoard(pub(crate) u64);
|
||||||
|
|
||||||
macro_rules! moves_getter {
|
macro_rules! moves_getter {
|
||||||
($getter_name:ident) => {
|
($getter_name:ident) => {
|
||||||
|
@ -71,14 +71,14 @@ impl BitBoard {
|
||||||
impl BitBoard {
|
impl BitBoard {
|
||||||
/// Return an Iterator over the occupied squares, starting from the leading
|
/// Return an Iterator over the occupied squares, starting from the leading
|
||||||
/// (most-significant bit) end of the field.
|
/// (most-significant bit) end of the field.
|
||||||
pub(crate) fn occupied_squares(&self) -> impl Iterator<Item = Square> {
|
pub fn occupied_squares(&self) -> impl Iterator<Item = Square> {
|
||||||
LeadingBitScanner::new(self.0).map(Square::from_index)
|
LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index(idx as u8) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an Iterator over the occupied squares, starting from the trailing
|
/// Return an Iterator over the occupied squares, starting from the trailing
|
||||||
/// (least-significant bit) end of the field.
|
/// (least-significant bit) end of the field.
|
||||||
pub(crate) fn occupied_squares_trailing(&self) -> impl Iterator<Item = Square> {
|
pub fn occupied_squares_trailing(&self) -> impl Iterator<Item = Square> {
|
||||||
LeadingBitScanner::new(self.0).map(Square::from_index)
|
LeadingBitScanner::new(self.0).map(|idx| unsafe { Square::from_index(idx as u8) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +243,8 @@ impl BitBoardBuilder {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{bitboard, Square};
|
use crate::bitboard;
|
||||||
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn display_and_debug() {
|
fn display_and_debug() {
|
|
@ -1,16 +1,19 @@
|
||||||
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
mod bit_scanner;
|
mod bit_scanner;
|
||||||
mod bitboard;
|
mod bitboard;
|
||||||
mod library;
|
mod library;
|
||||||
mod shifts;
|
mod shifts;
|
||||||
|
|
||||||
|
pub use bitboard::{BitBoard, BitBoardBuilder};
|
||||||
|
|
||||||
pub(crate) use bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
pub(crate) use bit_scanner::{LeadingBitScanner, TrailingBitScanner};
|
||||||
pub(crate) use bitboard::{BitBoard, BitBoardBuilder};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bitboard {
|
macro_rules! bitboard {
|
||||||
($($sq:ident),* $(,)?) => {
|
($($sq:ident),* $(,)?) => {
|
||||||
$crate::bitboard::BitBoardBuilder::empty()
|
$crate::BitBoardBuilder::empty()
|
||||||
$(.square($crate::Square::$sq))*
|
$(.square(chessfriend_core::Square::$sq))*
|
||||||
.build()
|
.build()
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::BitBoard;
|
use crate::BitBoard;
|
||||||
use crate::{square::Direction, Square};
|
use chessfriend_core::{Direction, Square};
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
pub(super) const RANKS: [BitBoard; 8] = [
|
pub(super) const RANKS: [BitBoard; 8] = [
|
|
@ -6,3 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chessfriend_core = { path = "../core" }
|
||||||
|
chessfriend_bitboard = { path = "../bitboard" }
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Piece, PlacedPiece},
|
piece::{Piece, PlacedPiece},
|
||||||
r#move::Castle,
|
r#move::Castle,
|
||||||
Color, File, Position, Rank, Square,
|
Color, Position,
|
||||||
};
|
};
|
||||||
|
use chessfriend_core::{File, Rank, Square};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[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))?;
|
write!(fen_string, "{}", empty_squares).map_err(|err| FenError::FmtError(err))?;
|
||||||
empty_squares = 0;
|
empty_squares = 0;
|
||||||
}
|
}
|
||||||
if rank != &Rank::One {
|
if rank != &Rank::ONE {
|
||||||
write!(fen_string, "/").map_err(|err| FenError::FmtError(err))?;
|
write!(fen_string, "/").map_err(|err| FenError::FmtError(err))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
pub mod fen;
|
pub mod fen;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod bitboard;
|
|
||||||
mod display;
|
mod display;
|
||||||
mod r#move;
|
mod r#move;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -12,11 +10,7 @@ mod move_generator;
|
||||||
pub mod piece;
|
pub mod piece;
|
||||||
mod position;
|
mod position;
|
||||||
mod sight;
|
mod sight;
|
||||||
mod square;
|
|
||||||
|
|
||||||
pub use piece::{Color, Piece};
|
pub use piece::{Color, Piece};
|
||||||
pub use position::{MoveBuilder as MakeMoveBuilder, Position, PositionBuilder};
|
pub use position::{MoveBuilder as MakeMoveBuilder, Position, PositionBuilder};
|
||||||
pub use r#move::{Castle, MakeMoveError, Move, MoveBuilder};
|
pub use r#move::{Castle, MakeMoveError, Move, MoveBuilder};
|
||||||
pub use square::{File, Rank, Square};
|
|
||||||
|
|
||||||
pub(crate) use bitboard::BitBoard;
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ macro_rules! piece {
|
||||||
$crate::piece::Piece::new($crate::piece::Color::$color, $crate::piece::Shape::$shape)
|
$crate::piece::Piece::new($crate::piece::Color::$color, $crate::piece::Shape::$shape)
|
||||||
};
|
};
|
||||||
($color:ident $shape:ident on $square:ident) => {
|
($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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::{
|
use crate::piece::{Piece, PlacedPiece, Shape};
|
||||||
piece::{Piece, PlacedPiece, Shape},
|
use chessfriend_core::{Rank, Square};
|
||||||
square::Rank,
|
|
||||||
Square,
|
|
||||||
};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub use castle::Castle;
|
pub use castle::Castle;
|
||||||
|
@ -20,7 +17,8 @@ pub enum MakeMoveError {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod castle {
|
mod castle {
|
||||||
use crate::{Color, Square};
|
use crate::Color;
|
||||||
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -248,8 +246,8 @@ impl MoveBuilder {
|
||||||
Shape::Pawn => {
|
Shape::Pawn => {
|
||||||
let from_rank = from.rank();
|
let from_rank = from.rank();
|
||||||
let to_rank = to.rank();
|
let to_rank = to.rank();
|
||||||
let is_white_double_push = from_rank == Rank::Two && to_rank == Rank::Four;
|
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_black_double_push = from_rank == Rank::SEVEN && to_rank == Rank::FIVE;
|
||||||
if is_white_double_push || is_black_double_push {
|
if is_white_double_push || is_black_double_push {
|
||||||
Kind::DoublePush
|
Kind::DoublePush
|
||||||
} else {
|
} else {
|
||||||
|
@ -421,8 +419,8 @@ mod move_formatter {
|
||||||
$crate::piece::Color::$color,
|
$crate::piece::Color::$color,
|
||||||
$crate::piece::Shape::$shape,
|
$crate::piece::Shape::$shape,
|
||||||
),
|
),
|
||||||
$crate::Square::$from_square,
|
chessfriend_core::Square::$from_square,
|
||||||
$crate::Square::$to_square,
|
chessfriend_core::Square::$to_square,
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
};
|
};
|
||||||
|
@ -432,15 +430,15 @@ mod move_formatter {
|
||||||
$crate::piece::Color::$color,
|
$crate::piece::Color::$color,
|
||||||
$crate::piece::Shape::$shape,
|
$crate::piece::Shape::$shape,
|
||||||
),
|
),
|
||||||
$crate::Square::$from_square,
|
chessfriend_core::Square::$from_square,
|
||||||
$crate::Square::$to_square,
|
chessfriend_core::Square::$to_square,
|
||||||
)
|
)
|
||||||
.capturing($crate::piece::PlacedPiece::new(
|
.capturing($crate::piece::PlacedPiece::new(
|
||||||
$crate::piece::Piece::new(
|
$crate::piece::Piece::new(
|
||||||
$crate::piece::Color::$captured_color,
|
$crate::piece::Color::$captured_color,
|
||||||
$crate::piece::Shape::$captured_shape,
|
$crate::piece::Shape::$captured_shape,
|
||||||
),
|
),
|
||||||
$crate::Square::$to_square,
|
chessfriend_core::Square::$to_square,
|
||||||
))
|
))
|
||||||
.build()
|
.build()
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
MoveBuilder, Position,
|
||||||
BitBoard, MoveBuilder, Position,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Direction;
|
||||||
|
|
||||||
move_generator_declaration!(ClassicalMoveGenerator);
|
move_generator_declaration!(ClassicalMoveGenerator);
|
||||||
|
|
||||||
|
@ -60,7 +61,8 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{piece, piece::Color, position, position::DiagramFormatter, BitBoard};
|
use crate::{piece, piece::Color, position, position::DiagramFormatter};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classical_single_bishop_bitboard() {
|
fn classical_single_bishop_bitboard() {
|
||||||
|
|
|
@ -7,8 +7,9 @@ use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
r#move::Castle,
|
r#move::Castle,
|
||||||
BitBoard, Move, MoveBuilder, Position,
|
Move, MoveBuilder, Position,
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
|
||||||
move_generator_declaration!(KingMoveGenerator, struct);
|
move_generator_declaration!(KingMoveGenerator, struct);
|
||||||
move_generator_declaration!(KingMoveGenerator, new);
|
move_generator_declaration!(KingMoveGenerator, new);
|
||||||
|
@ -76,7 +77,8 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::Square;
|
use chessfriend_bitboard::bitboard;
|
||||||
|
use chessfriend_core::Square;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
BitBoard, MoveBuilder, Position,
|
MoveBuilder, Position,
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
|
||||||
move_generator_declaration!(KnightMoveGenerator);
|
move_generator_declaration!(KnightMoveGenerator);
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ impl<'pos> MoveGeneratorInternal for KnightMoveGenerator<'pos> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{piece, position, Move, Square};
|
use crate::{piece, position, Move};
|
||||||
|
use chessfriend_core::Square;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -14,8 +14,9 @@ pub(crate) use move_set::MoveSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
Move, Position, Square,
|
Move, Position,
|
||||||
};
|
};
|
||||||
|
use chessfriend_core::Square;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
trait MoveGenerator {
|
trait MoveGenerator {
|
||||||
|
@ -34,7 +35,10 @@ macro_rules! move_generator_declaration {
|
||||||
pub(super) struct $name<'pos> {
|
pub(super) struct $name<'pos> {
|
||||||
position: &'pos $crate::Position,
|
position: &'pos $crate::Position,
|
||||||
color: $crate::piece::Color,
|
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) => {
|
($name:ident, new) => {
|
||||||
|
@ -54,12 +58,11 @@ macro_rules! move_generator_declaration {
|
||||||
self.move_sets.values().map(|set| set.moves()).flatten()
|
self.move_sets.values().map(|set| set.moves()).flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bitboard(&self) -> $crate::BitBoard {
|
fn bitboard(&self) -> chessfriend_bitboard::BitBoard {
|
||||||
self.move_sets
|
self.move_sets.values().fold(
|
||||||
.values()
|
chessfriend_bitboard::BitBoard::empty(),
|
||||||
.fold($crate::BitBoard::empty(), |partial, mv_set| {
|
|partial, mv_set| partial | mv_set.bitboard(),
|
||||||
partial | mv_set.bitboard()
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,8 @@ impl<'a> Moves<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{piece::PlacedPiece, BitBoard, Move};
|
use crate::{piece::PlacedPiece, Move};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct BitBoardSet {
|
struct BitBoardSet {
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, Shape},
|
piece::{Color, Piece, Shape},
|
||||||
BitBoard, Move, MoveBuilder, Position,
|
Move, MoveBuilder, Position,
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
|
||||||
enum MoveList {
|
enum MoveList {
|
||||||
Quiet = 0,
|
Quiet = 0,
|
||||||
|
@ -246,7 +247,8 @@ impl<'pos> Iterator for PawnMoveGenerator<'pos> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::position::DiagramFormatter;
|
use crate::position::DiagramFormatter;
|
||||||
use crate::{piece, Position, Square};
|
use crate::{piece, Position};
|
||||||
|
use chessfriend_core::Square;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
MoveBuilder, Position,
|
||||||
BitBoard, MoveBuilder, Position,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Direction;
|
||||||
|
|
||||||
move_generator_declaration!(ClassicalMoveGenerator);
|
move_generator_declaration!(ClassicalMoveGenerator);
|
||||||
|
|
||||||
|
@ -66,7 +67,8 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{piece, position, position::DiagramFormatter, BitBoard, Color};
|
use crate::{piece, position, position::DiagramFormatter, Color};
|
||||||
|
use chessfriend_bitboard::{bitboard, BitBoard};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classical_single_queen_bitboard() {
|
fn classical_single_queen_bitboard() {
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
MoveBuilder, Position,
|
||||||
BitBoard, MoveBuilder, Position,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Direction;
|
||||||
|
|
||||||
move_generator_declaration!(ClassicalMoveGenerator);
|
move_generator_declaration!(ClassicalMoveGenerator);
|
||||||
|
|
||||||
|
@ -62,9 +63,9 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{piece::Piece, position, position::DiagramFormatter, Color, Position};
|
||||||
piece::Piece, position, position::DiagramFormatter, BitBoard, Color, Position, Square,
|
use chessfriend_bitboard::{bitboard, BitBoard};
|
||||||
};
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classical_single_rook_bitboard() {
|
fn classical_single_rook_bitboard() {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::{
|
use crate::display::{ASCIIDisplay, FENDisplay, UnicodeDisplay};
|
||||||
display::{ASCIIDisplay, FENDisplay, UnicodeDisplay},
|
use chessfriend_core::Square;
|
||||||
Square,
|
|
||||||
};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ use crate::{
|
||||||
piece::{PlacedPiece, Shape},
|
piece::{PlacedPiece, Shape},
|
||||||
position::flags::Flags,
|
position::flags::Flags,
|
||||||
r#move::Castle,
|
r#move::Castle,
|
||||||
square::Direction,
|
Color, MakeMoveError, Move, Piece, Position,
|
||||||
BitBoard, Color, MakeMoveError, Move, Piece, Position, Square,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::{Direction, Square};
|
||||||
|
|
||||||
/// A position builder that builds a new position by making a move.
|
/// A position builder that builds a new position by making a move.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoardBuilder,
|
|
||||||
piece::{PlacedPiece, Shape},
|
piece::{PlacedPiece, Shape},
|
||||||
position::{flags::Flags, piece_sets::PieceBitBoards},
|
position::{flags::Flags, piece_sets::PieceBitBoards},
|
||||||
r#move::Castle,
|
r#move::Castle,
|
||||||
square::{Direction, Rank},
|
Color, MakeMoveError, Move, Piece, Position,
|
||||||
BitBoard, Color, MakeMoveError, Move, Piece, Position, Square,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_core::{Rank, Square};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -100,7 +99,7 @@ impl Builder {
|
||||||
// Pawns cannot be placed on the first (back) rank of their side,
|
// Pawns cannot be placed on the first (back) rank of their side,
|
||||||
// and cannot be placed on the final rank without a promotion.
|
// and cannot be placed on the final rank without a promotion.
|
||||||
let rank = piece.square().rank();
|
let rank = piece.square().rank();
|
||||||
return rank != Rank::One && rank != Rank::Eight;
|
return rank != Rank::ONE && rank != Rank::EIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -109,8 +108,8 @@ impl Builder {
|
||||||
|
|
||||||
impl Default for Builder {
|
impl Default for Builder {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let white_king_square = Square::king_starting_square(Color::White);
|
let white_king_square = Square::E1;
|
||||||
let black_king_square = Square::king_starting_square(Color::Black);
|
let black_king_square = Square::E8;
|
||||||
|
|
||||||
let pieces = BTreeMap::from_iter([
|
let pieces = BTreeMap::from_iter([
|
||||||
(white_king_square, piece!(White King)),
|
(white_king_square, piece!(White King)),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::{File, Position, Rank, Square};
|
use crate::Position;
|
||||||
|
use chessfriend_core::{File, Rank, Square};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub struct DiagramFormatter<'a>(&'a Position);
|
pub struct DiagramFormatter<'a>(&'a Position);
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Piece, PlacedPiece},
|
piece::{Piece, PlacedPiece},
|
||||||
BitBoard, Color, Square,
|
Color,
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum PlacePieceStrategy {
|
pub enum PlacePieceStrategy {
|
||||||
|
@ -124,7 +126,7 @@ impl PieceBitBoards {
|
||||||
|
|
||||||
impl FromIterator<PlacedPiece> for PieceBitBoards {
|
impl FromIterator<PlacedPiece> for PieceBitBoards {
|
||||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
||||||
let mut pieces = Self::default();
|
let mut pieces: Self = Default::default();
|
||||||
|
|
||||||
for piece in iter {
|
for piece in iter {
|
||||||
let _ = pieces.place_piece(&piece);
|
let _ = pieces.place_piece(&piece);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use super::Position;
|
use super::Position;
|
||||||
use crate::piece::{Color, Piece, PlacedPiece, Shape};
|
use crate::piece::{Color, Piece, PlacedPiece, Shape};
|
||||||
use crate::BitBoard;
|
use chessfriend_bitboard::BitBoard;
|
||||||
use crate::Square;
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
pub struct Pieces<'a> {
|
pub struct Pieces<'a> {
|
||||||
color: Color,
|
color: Color,
|
||||||
|
@ -76,7 +76,6 @@ impl<'a> Iterator for Pieces<'a> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::piece::{Color, Piece, Shape};
|
use crate::piece::{Color, Piece, Shape};
|
||||||
use crate::Square;
|
|
||||||
use crate::{Position, PositionBuilder};
|
use crate::{Position, PositionBuilder};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,10 @@ use crate::{
|
||||||
position::DiagramFormatter,
|
position::DiagramFormatter,
|
||||||
r#move::Castle,
|
r#move::Castle,
|
||||||
sight::Sight,
|
sight::Sight,
|
||||||
BitBoard, Move, Square,
|
Move,
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Square;
|
||||||
use std::{cell::OnceCell, fmt};
|
use std::{cell::OnceCell, fmt};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -266,7 +268,8 @@ impl fmt::Display for Position {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{position, Castle, Color, Position, Square};
|
use crate::{position, Castle, Color, Position};
|
||||||
|
use chessfriend_core::Square;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn piece_on_square() {
|
fn piece_on_square() {
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
piece::{Color, PlacedPiece, Shape},
|
piece::{Color, PlacedPiece, Shape},
|
||||||
square::Direction,
|
Position,
|
||||||
BitBoard, Position,
|
|
||||||
};
|
};
|
||||||
|
use chessfriend_bitboard::BitBoard;
|
||||||
|
use chessfriend_core::Direction;
|
||||||
|
|
||||||
pub(crate) trait Sight {
|
pub(crate) trait Sight {
|
||||||
fn sight_in_position(&self, position: &Position) -> BitBoard;
|
fn sight_in_position(&self, position: &Position) -> BitBoard;
|
||||||
|
@ -174,7 +175,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod pawn {
|
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));
|
sight_test!(e4_pawn, piece!(White Pawn on E4), bitboard!(D5, F5));
|
||||||
|
|
||||||
|
@ -233,6 +236,7 @@ mod tests {
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod knight {
|
mod knight {
|
||||||
use crate::sight::Sight;
|
use crate::sight::Sight;
|
||||||
|
use chessfriend_bitboard::bitboard;
|
||||||
|
|
||||||
sight_test!(
|
sight_test!(
|
||||||
f6_knight,
|
f6_knight,
|
||||||
|
@ -243,6 +247,7 @@ mod tests {
|
||||||
|
|
||||||
mod bishop {
|
mod bishop {
|
||||||
use crate::sight::Sight;
|
use crate::sight::Sight;
|
||||||
|
use chessfriend_bitboard::bitboard;
|
||||||
|
|
||||||
sight_test!(
|
sight_test!(
|
||||||
c2_bishop,
|
c2_bishop,
|
||||||
|
@ -253,6 +258,7 @@ mod tests {
|
||||||
|
|
||||||
mod rook {
|
mod rook {
|
||||||
use crate::sight::Sight;
|
use crate::sight::Sight;
|
||||||
|
use chessfriend_bitboard::bitboard;
|
||||||
|
|
||||||
sight_test!(
|
sight_test!(
|
||||||
g3_rook,
|
g3_rook,
|
||||||
|
|
|
@ -1,360 +0,0 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
|
||||||
|
|
||||||
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<Self> {
|
|
||||||
$(
|
|
||||||
#[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<char> for File {
|
|
||||||
fn into(self) -> char {
|
|
||||||
('a' as u8 + self as u8) as char
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<char> for File {
|
|
||||||
type Error = ParseFileError;
|
|
||||||
|
|
||||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
|
||||||
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::<char>::into(*self).to_uppercase())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<char> for Rank {
|
|
||||||
fn into(self) -> char {
|
|
||||||
('1' as u8 + self as u8) as char
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<char> for Rank {
|
|
||||||
type Error = ParseFileError;
|
|
||||||
|
|
||||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
|
||||||
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::<char>::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<Square, ParseSquareError> {
|
|
||||||
s.parse()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn neighbor(self, direction: Direction) -> Option<Square> {
|
|
||||||
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<Self, Self::Err> {
|
|
||||||
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<Self, Self::Error> {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "core"
|
name = "chessfriend_core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chessfriend_core = { path = "../core" }
|
||||||
board = { path = "../board" }
|
board = { path = "../board" }
|
||||||
clap = { version = "4.4.12", features = ["derive"] }
|
clap = { version = "4.4.12", features = ["derive"] }
|
||||||
rustyline = "13.0.0"
|
rustyline = "13.0.0"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use board::piece::{Color, Piece, Shape};
|
use board::piece::{Color, Piece, Shape};
|
||||||
use board::{Position, Square};
|
use board::Position;
|
||||||
|
use chessfriend_core::Square;
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::DefaultEditor;
|
use rustyline::DefaultEditor;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue