use core::fmt;
use core::mem::transmute;
use crate::{piece::PROM_PIECES, Color, Piece, Square};
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default, Hash)]
pub struct Move(pub u16);
impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_promotion() {
write!(
f,
"{}{}{}",
self.get_src(),
self.get_dest(),
self.get_prom(Color::Black).to_char()
)
} else {
write!(f, "{}{}", self.get_src(), self.get_dest())
}
}
}
impl PartialEq<&str> for Move {
fn eq(&self, other: &&str) -> bool {
let mut move_str: [u8; 6] = [0u8; 6];
let mut pos: usize = 0;
let src: &str = self.get_src().to_str();
let dest: &str = self.get_dest().to_str();
move_str[pos..pos + src.len()].copy_from_slice(src.as_bytes());
pos += src.len();
move_str[pos..pos + dest.len()].copy_from_slice(dest.as_bytes());
pos += dest.len();
if self.is_promotion() {
move_str[pos] = self.get_prom(Color::Black).to_char() as u8;
pos += 1;
}
let move_as_str: &str = core::str::from_utf8(&move_str[..pos]).unwrap_or("");
move_as_str == *other
}
}
const SRC_MASK: u16 = 0b00000000_00111111;
const DEST_MASK: u16 = 0b00001111_11000000;
const TYPE_MASK: u16 = 0b11110000_00000000;
const PROM_MASK: u16 = 0b10000000_00000000;
const CAP_MASK: u16 = 0b01000000_00000000;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
#[repr(u8)]
pub enum MoveType {
Quiet = 0b0000,
DoublePawn = 0b0001,
KingCastle = 0b0010,
QueenCastle = 0b0011,
Capture = 0b0100,
EnPassant = 0b0101,
PromotionKnight = 0b1000,
PromotionBishop = 0b1001,
PromotionRook = 0b1010,
PromotionQueen = 0b1011,
CapPromoKnight = 0b1100,
CapPromoBishop = 0b1101,
CapPromoRook = 0b1110,
CapPromoQueen = 0b1111,
}
impl Move {
#[inline(always)]
pub const fn null() -> Self {
Self(0)
}
#[inline(always)]
pub const fn is_null(self) -> bool {
self.0 == 0
}
#[inline(always)]
pub const fn new(src: Square, dest: Square, move_type: MoveType) -> Self {
Self(((move_type as u16) << 12) | ((dest as u16) << 6) | (src as u16))
}
#[inline(always)]
pub const fn get_dest(self) -> Square {
unsafe { transmute((((self.0 & DEST_MASK) >> 6) as u8) & 63) }
}
#[inline(always)]
pub const fn get_src(self) -> Square {
unsafe { transmute(((self.0 & SRC_MASK) as u8) & 63) }
}
#[inline(always)]
pub const fn get_type(self) -> MoveType {
unsafe { transmute((((self.0 & TYPE_MASK) >> 12) as u8) & 15) }
}
#[inline(always)]
pub const fn get_prom(self, color: Color) -> Piece {
PROM_PIECES[color as usize][self.flag() as usize & 0b011]
}
#[inline(always)]
pub const fn is_promotion(self) -> bool {
(self.0 & PROM_MASK) != 0
}
#[inline(always)]
pub const fn is_underpromotion(self) -> bool {
self.is_promotion() && self.flag() & 0b1011 != 0b1011
}
#[inline(always)]
pub const fn is_capture(self) -> bool {
((self.0 & CAP_MASK) >> 14) == 1
}
#[inline(always)]
pub const fn is_quiet(self) -> bool {
self.flag() == 0
}
#[inline(always)]
pub const fn flag(self) -> u16 {
self.0 >> 12
}
}