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

@ -5,19 +5,29 @@ use chessfriend_board::castle::Castle;
use chessfriend_core::{Rank, Shape, Square};
use std::fmt;
/// A single player's move. In chess parlance, this is a "ply".
/// A single player's move. In game theory parlance, this is a "ply".
///
/// ## TODO
///
/// - Rename this class `Ply`.
///
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct Move(pub(crate) u16);
impl Move {
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn origin_square(&self) -> Square {
((self.0 >> 4) & 0b111111).try_into().unwrap()
((self.0 >> 4) & 0b111_111).try_into().unwrap()
}
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn target_square(&self) -> Square {
(self.0 >> 10).try_into().unwrap()
}
#[must_use]
pub fn capture_square(&self) -> Option<Square> {
if self.is_en_passant() {
let target_square = self.target_square();
@ -35,18 +45,22 @@ impl Move {
None
}
#[must_use]
pub fn is_quiet(&self) -> bool {
self.flags() == Kind::Quiet as u16
}
#[must_use]
pub fn is_double_push(&self) -> bool {
self.flags() == Kind::DoublePush as u16
}
#[must_use]
pub fn is_castle(&self) -> bool {
self.castle().is_some()
}
#[must_use]
pub fn castle(&self) -> Option<Castle> {
match self.flags() {
0b0010 => Some(Castle::KingSide),
@ -55,18 +69,22 @@ impl Move {
}
}
#[must_use]
pub fn is_capture(&self) -> bool {
(self.0 & 0b0100) != 0
}
#[must_use]
pub fn is_en_passant(&self) -> bool {
self.flags() == 0b0101
}
#[must_use]
pub fn is_promotion(&self) -> bool {
(self.0 & 0b1000) != 0
}
#[must_use]
pub fn promotion(&self) -> Option<Shape> {
if !self.is_promotion() {
return None;
@ -80,18 +98,22 @@ impl Move {
_ => unreachable!(),
})
}
}
impl Move {
#[inline]
fn flags(&self) -> u16 {
fn flags(self) -> u16 {
self.0 & 0b1111
}
#[inline]
fn special(&self) -> u16 {
fn special(self) -> u16 {
self.0 & 0b11
}
}
fn _transfer_char(&self) -> char {
impl Move {
fn _transfer_char(self) -> char {
if self.is_capture() || self.is_en_passant() {
'x'
} else {
@ -103,22 +125,19 @@ impl Move {
impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(castle) = self.castle() {
match castle {
Castle::KingSide => return write!(f, "0-0"),
Castle::QueenSide => return write!(f, "0-0-0"),
}
return match castle {
Castle::KingSide => write!(f, "0-0"),
Castle::QueenSide => write!(f, "0-0-0"),
};
}
write!(
f,
"{}{}{}",
self.origin_square(),
self._transfer_char(),
self.target_square()
)?;
let origin = self.origin_square();
let target = self.target_square();
let transfer_char = self._transfer_char();
write!(f, "{origin}{transfer_char}{target}")?;
if let Some(promotion) = self.promotion() {
write!(f, "={}", promotion)?;
write!(f, "={promotion}")?;
} else if self.is_en_passant() {
write!(f, " e.p.")?;
}