use crate::game::piece::Piece;
use crate::game::square::Square;
use std::fmt::{Display, Formatter};
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct ChessMove(u16);
impl ChessMove {
pub fn new(from: u8, to: u8, move_type: ChessMoveType) -> Self {
Self(((from as u16) << 10) | (((to & 0b111111) as u16) << 4) | (move_type as u16))
}
pub fn all_promotions(from: u8, to: u8) -> Vec<Self> {
vec![
Self::new(from, to, ChessMoveType::KnightPromotion),
Self::new(from, to, ChessMoveType::BishopPromotion),
Self::new(from, to, ChessMoveType::RookPromotion),
Self::new(from, to, ChessMoveType::QueenPromotion),
]
}
pub fn all_promotions_capture(from: u8, to: u8) -> Vec<Self> {
vec![
Self::new(from, to, ChessMoveType::KnightPromotionCapture),
Self::new(from, to, ChessMoveType::BishopPromotionCapture),
Self::new(from, to, ChessMoveType::RookPromotionCapture),
Self::new(from, to, ChessMoveType::QueenPromotionCapture),
]
}
pub fn get_from(&self) -> u8 {
(self.0 >> 10) as u8
}
pub fn get_to(&self) -> u8 {
((self.0 & 0b00000011_11110000) >> 4) as u8
}
pub fn get_type(&self) -> ChessMoveType {
ChessMoveType::from(self.0 as u8)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum ChessMoveType {
Quiet = 0,
DoublePawnPush = 1,
KingCastle = 2,
QueenCastle = 3,
Capture = 4,
EnPassant = 5,
Reserved6 = 6,
Reserved7 = 7,
KnightPromotion = 8,
BishopPromotion = 9,
RookPromotion = 10,
QueenPromotion = 11,
KnightPromotionCapture = 12,
BishopPromotionCapture = 13,
RookPromotionCapture = 14,
QueenPromotionCapture = 15,
}
impl ChessMoveType {
pub fn is_capture(&self) -> bool {
(((*self as u8) >> 2) & 1) == 1
}
pub fn is_promotion(&self) -> bool {
(*self as u8) >= 8
}
pub fn promotion_piece(&self) -> Option<Piece> {
match self {
Self::KnightPromotion | Self::KnightPromotionCapture => Some(Piece::Knight),
Self::BishopPromotion | Self::BishopPromotionCapture => Some(Piece::Bishop),
Self::RookPromotion | Self::RookPromotionCapture => Some(Piece::Rook),
Self::QueenPromotion | Self::QueenPromotionCapture => Some(Piece::Queen),
_ => None,
}
}
}
impl From<u8> for ChessMoveType {
fn from(value: u8) -> Self {
match value & 0b1111 {
0 => ChessMoveType::Quiet,
1 => ChessMoveType::DoublePawnPush,
2 => ChessMoveType::KingCastle,
3 => ChessMoveType::QueenCastle,
4 => ChessMoveType::Capture,
5 => ChessMoveType::EnPassant,
6 => ChessMoveType::Reserved6,
7 => ChessMoveType::Reserved7,
8 => ChessMoveType::KnightPromotion,
9 => ChessMoveType::BishopPromotion,
10 => ChessMoveType::RookPromotion,
11 => ChessMoveType::QueenPromotion,
12 => ChessMoveType::KnightPromotionCapture,
13 => ChessMoveType::BishopPromotionCapture,
14 => ChessMoveType::RookPromotionCapture,
15 => ChessMoveType::QueenPromotionCapture,
_ => unreachable!(),
}
}
}
impl Display for ChessMove {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let from = Square::new(self.get_from()).to_string().to_lowercase();
let to = Square::new(self.get_to()).to_string().to_lowercase();
match self.get_type() {
ChessMoveType::Quiet => write!(f, "{}-{}", from, to),
ChessMoveType::DoublePawnPush => write!(f, "{} DPP", from),
ChessMoveType::KingCastle => write!(f, "KC"),
ChessMoveType::QueenCastle => write!(f, "QC"),
ChessMoveType::Capture => write!(f, "{}-{} C", from, to),
ChessMoveType::EnPassant => write!(f, "{}-{} EP", from, to),
ChessMoveType::Reserved6 => write!(f, "R6"),
ChessMoveType::Reserved7 => write!(f, "R7"),
ChessMoveType::KnightPromotion => write!(f, "{}-{} PN", from, to),
ChessMoveType::BishopPromotion => write!(f, "{}-{} PB", from, to),
ChessMoveType::RookPromotion => write!(f, "{}-{} PR", from, to),
ChessMoveType::QueenPromotion => write!(f, "{}-{} PQ", from, to),
ChessMoveType::KnightPromotionCapture => write!(f, "{}-{} PN C", from, to),
ChessMoveType::BishopPromotionCapture => write!(f, "{}-{} PB C", from, to),
ChessMoveType::RookPromotionCapture => write!(f, "{}-{} PR C", from, to),
ChessMoveType::QueenPromotionCapture => write!(f, "{}-{} PQ C", from, to),
}
}
}