Move a bunch of stuff from the position::move module over to a new chessfriend_moves crate
This commit is contained in:
parent
1958c1a50e
commit
f69c7d4c96
6 changed files with 257 additions and 2 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -74,12 +74,11 @@ name = "chessfriend_core"
|
|||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "chessfriend_move_generator"
|
||||
name = "chessfriend_moves"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chessfriend_bitboard",
|
||||
"chessfriend_core",
|
||||
"chessfriend_position",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -3,6 +3,7 @@ members = [
|
|||
"bitboard",
|
||||
"core",
|
||||
"explorer",
|
||||
"moves",
|
||||
"position",
|
||||
]
|
||||
resolver = "2"
|
||||
|
|
10
moves/Cargo.toml
Normal file
10
moves/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "chessfriend_moves"
|
||||
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" }
|
||||
chessfriend_bitboard = { path = "../bitboard" }
|
110
moves/src/castle.rs
Normal file
110
moves/src/castle.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Square};
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Castle {
|
||||
KingSide = 0b10,
|
||||
QueenSide = 0b11,
|
||||
}
|
||||
|
||||
pub(crate) struct CastlingParameters {
|
||||
clear_squares: BitBoard,
|
||||
check_squares: BitBoard,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Squares {
|
||||
pub king: Square,
|
||||
pub rook: Square,
|
||||
}
|
||||
|
||||
impl Castle {
|
||||
pub const ALL: [Castle; 2] = [Castle::KingSide, Castle::QueenSide];
|
||||
|
||||
const STARTING_SQUARES: [[Squares; 2]; 2] = [
|
||||
[
|
||||
Squares {
|
||||
king: Square::E1,
|
||||
rook: Square::H1,
|
||||
},
|
||||
Squares {
|
||||
king: Square::E1,
|
||||
rook: Square::A1,
|
||||
},
|
||||
],
|
||||
[
|
||||
Squares {
|
||||
king: Square::E8,
|
||||
rook: Square::H8,
|
||||
},
|
||||
Squares {
|
||||
king: Square::E8,
|
||||
rook: Square::A8,
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
const TARGET_SQUARES: [[Squares; 2]; 2] = [
|
||||
[
|
||||
Squares {
|
||||
king: Square::G1,
|
||||
rook: Square::F1,
|
||||
},
|
||||
Squares {
|
||||
king: Square::C1,
|
||||
rook: Square::D1,
|
||||
},
|
||||
],
|
||||
[
|
||||
Squares {
|
||||
king: Square::G8,
|
||||
rook: Square::F8,
|
||||
},
|
||||
Squares {
|
||||
king: Square::C8,
|
||||
rook: Square::D8,
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
pub(crate) fn starting_squares(&self, color: Color) -> &'static Squares {
|
||||
&Castle::STARTING_SQUARES[color as usize][self.into_index()]
|
||||
}
|
||||
|
||||
pub(crate) fn target_squares(&self, color: Color) -> &'static Squares {
|
||||
&Castle::TARGET_SQUARES[color as usize][self.into_index()]
|
||||
}
|
||||
|
||||
pub(crate) fn into_index(&self) -> usize {
|
||||
match self {
|
||||
Castle::KingSide => 0,
|
||||
Castle::QueenSide => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parameters(&self) -> CastlingParameters {
|
||||
match self {
|
||||
Castle::KingSide => CastlingParameters {
|
||||
clear_squares: BitBoard::new(0b01100000),
|
||||
check_squares: BitBoard::new(0b01110000),
|
||||
},
|
||||
Castle::QueenSide => CastlingParameters {
|
||||
clear_squares: BitBoard::new(0b00001110),
|
||||
check_squares: BitBoard::new(0b00011100),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CastlingParameters {
|
||||
pub fn clear_squares(&self) -> &BitBoard {
|
||||
&self.clear_squares
|
||||
}
|
||||
|
||||
pub fn check_squares(&self) -> &BitBoard {
|
||||
&self.check_squares
|
||||
}
|
||||
}
|
8
moves/src/lib.rs
Normal file
8
moves/src/lib.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
mod builder;
|
||||
mod castle;
|
||||
mod moves;
|
||||
|
||||
pub use builder::Builder;
|
||||
pub use moves::Move;
|
127
moves/src/moves.rs
Normal file
127
moves/src/moves.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::castle::Castle;
|
||||
use chessfriend_core::{PlacedPiece, Shape, Square};
|
||||
use std::fmt;
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum PromotableShape {
|
||||
Knight = 0b00,
|
||||
Bishop = 0b01,
|
||||
Rook = 0b10,
|
||||
Queen = 0b11,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum Kind {
|
||||
Quiet = 0b00,
|
||||
DoublePush = 0b01,
|
||||
Castle(Castle),
|
||||
Capture(PlacedPiece) = 0b0100,
|
||||
EnPassantCapture(PlacedPiece) = 0b0101,
|
||||
Promotion(PromotableShape) = 0b1000,
|
||||
CapturePromotion(PlacedPiece, PromotableShape) = 0b1100,
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
fn bits(&self) -> u16 {
|
||||
match self {
|
||||
Self::Promotion(shape) => self.discriminant() | *shape as u16,
|
||||
Self::CapturePromotion(_, shape) => self.discriminant() | *shape as u16,
|
||||
Self::Castle(castle) => *castle as u16,
|
||||
_ => self.discriminant(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the discriminant value. This implementation is copied from the Rust docs.
|
||||
/// See https://doc.rust-lang.org/std/mem/fn.discriminant.html
|
||||
fn discriminant(&self) -> u16 {
|
||||
unsafe { *<*const _>::from(self).cast::<u16>() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Kind {
|
||||
fn default() -> Self {
|
||||
Self::Quiet
|
||||
}
|
||||
}
|
||||
|
||||
/// A single player's move. In chess parlance, this is a "ply".
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct Move(pub(crate) u16);
|
||||
|
||||
impl Move {
|
||||
pub fn from_square(&self) -> Square {
|
||||
((self.0 >> 4) & 0b111111).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn to_square(&self) -> Square {
|
||||
(self.0 >> 10).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn is_quiet(&self) -> bool {
|
||||
self.flags() == Kind::Quiet.discriminant()
|
||||
}
|
||||
|
||||
pub fn is_double_push(&self) -> bool {
|
||||
self.flags() == Kind::DoublePush.discriminant()
|
||||
}
|
||||
|
||||
pub fn is_castle(&self) -> bool {
|
||||
self.castle().is_some()
|
||||
}
|
||||
|
||||
pub fn castle(&self) -> Option<Castle> {
|
||||
match self.flags() {
|
||||
0b0010 => Some(Castle::KingSide),
|
||||
0b0011 => Some(Castle::QueenSide),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_capture(&self) -> bool {
|
||||
(self.0 & 0b0100) != 0
|
||||
}
|
||||
|
||||
pub fn is_en_passant(&self) -> bool {
|
||||
self.flags() == 0b0101
|
||||
}
|
||||
|
||||
pub fn is_promotion(&self) -> bool {
|
||||
(self.0 & 0b1000) != 0
|
||||
}
|
||||
|
||||
pub fn promotion(&self) -> Option<Shape> {
|
||||
if !self.is_promotion() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(match self.special() {
|
||||
0b00 => Shape::Knight,
|
||||
0b01 => Shape::Bishop,
|
||||
0b10 => Shape::Rook,
|
||||
0b11 => Shape::Queen,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flags(&self) -> u16 {
|
||||
self.0 & 0b1111
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn special(&self) -> u16 {
|
||||
self.0 & 0b11
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Move {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("Move")
|
||||
.field(&format_args!("{:08b}", &self.0))
|
||||
.finish()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue