use std::fmt;
use std::cmp::{Ordering,PartialEq,PartialOrd,Ord};
use super::*;
use super::sq::SQ;
const SRC_MASK: u16 = 0b0000_000000_111111;
const DST_MASK: u16 = 0b0000_111111_000000;
const FROM_TO_MASK: u16 = 0b0000_111111_111111;
const PR_MASK: u16 = 0b1000_000000_000000;
const CP_MASK: u16 = 0b0100_000000_000000;
const FLAG_MASK: u16 = 0b1111_000000_000000;
const SP_MASK: u16 = 0b0011_000000_000000;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(transparent)]
pub struct BitMove {
data: u16,
}
#[derive(Copy, Clone, PartialEq)]
pub enum MoveFlag {
Promotion {
capture: bool,
prom: PieceType
},
Castle {
king_side: bool
},
DoublePawnPush,
Capture {
ep_capture: bool
},
QuietMove,
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum MoveType {
Normal = 0, Castle = 1, EnPassant = 5, Promotion = 8, }
#[derive(Copy, Clone, PartialEq)]
pub struct PreMoveInfo {
pub src: SQ,
pub dst: SQ,
pub flags: MoveFlag,
}
impl fmt::Display for BitMove {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.stringify())
}
}
impl BitMove {
pub const FLAG_QUIET: u16 = 0b0000;
pub const FLAG_DOUBLE_PAWN: u16 = 0b0001;
pub const FLAG_KING_CASTLE: u16 = 0b0010;
pub const FLAG_QUEEN_CASTLE: u16 = 0b0011;
pub const FLAG_CAPTURE: u16 = 0b0100;
pub const FLAG_EP: u16 = 0b0101;
pub const ILLEGAL_FLAG_1: u16 = 0b0110;
pub const ILLEGAL_FLAG_2: u16 = 0b0111;
pub const FLAG_PROMO_N: u16 = 0b1000;
pub const FLAG_PROMO_B: u16 = 0b1001;
pub const FLAG_PROMO_R: u16 = 0b1010;
pub const FLAG_PROMO_Q: u16 = 0b1011;
pub const FLAG_PROMO_CAP_N: u16 = 0b1100;
pub const FLAG_PROMO_CAP_B: u16 = 0b1101;
pub const FLAG_PROMO_CAP_R: u16 = 0b1110;
pub const FLAG_PROMO_CAP_Q: u16 = 0b1111;
#[inline]
pub const fn new(input: u16) -> BitMove {
BitMove { data: input }
}
#[inline(always)]
pub const fn make_quiet(src: SQ, dst: SQ) -> BitMove {
BitMove::make(BitMove::FLAG_QUIET,src,dst)
}
#[inline(always)]
pub const fn make_pawn_push(src: SQ, dst: SQ) -> BitMove {
BitMove::make(BitMove::FLAG_DOUBLE_PAWN,src,dst)
}
#[inline(always)]
pub const fn make_capture(src: SQ, dst: SQ) -> BitMove {
BitMove::make(BitMove::FLAG_CAPTURE,src,dst)
}
#[inline(always)]
pub const fn make_ep_capture(src: SQ, dst: SQ) -> BitMove {
BitMove::make(BitMove::FLAG_EP,src,dst)
}
#[inline(always)]
pub const fn make(flag_bits: u16, src: SQ, dst: SQ) -> BitMove {
BitMove { data: (flag_bits << 12) | src.0 as u16 | ((dst.0 as u16) << 6) }
}
#[inline(always)]
fn promotion_piece_flag(piece: PieceType) -> u16 {
match piece {
PieceType::R => 2,
PieceType::B => 1,
PieceType::N => 0,
PieceType::Q | _ => 3,
}
}
#[inline]
pub fn init(info: PreMoveInfo) -> BitMove {
let src = info.src.0 as u16;
let dst = (info.dst.0 as u16) << 6;
let flags = info.flags;
let flag_bits: u16 = match flags {
MoveFlag::Promotion { capture, prom } => {
let p_bit: u16 = BitMove::promotion_piece_flag(prom);
let cp_bit = if capture { 4 } else { 0 };
p_bit + cp_bit + 8
}
MoveFlag::Capture { ep_capture } => {
if ep_capture {
5
} else {
4
}
}
MoveFlag::Castle { king_side } => {
if king_side {
2
} else {
3
}
}
MoveFlag::DoublePawnPush => 1,
MoveFlag::QuietMove => 0,
};
BitMove { data: (flag_bits << 12) | src | dst }
}
#[inline]
pub const fn null() -> Self {
BitMove { data: 0 }
}
#[inline]
pub const fn is_null(self) -> bool {
self.data == 0
}
#[inline(always)]
pub const fn is_capture(self) -> bool {
((self.data & CP_MASK) >> 14) == 1
}
#[inline(always)]
pub const fn is_quiet_move(self) -> bool {
self.flag() == 0
}
#[inline(always)]
pub const fn is_promo(self) -> bool {
(self.data & PR_MASK) != 0
}
#[inline(always)]
pub const fn get_dest(self) -> SQ {
SQ(self.get_dest_u8())
}
#[inline(always)]
pub const fn get_dest_u8(self) -> u8 {
((self.data & DST_MASK) >> 6) as u8
}
#[inline(always)]
pub const fn get_src(self) -> SQ {
SQ(self.get_src_u8())
}
#[inline(always)]
pub const fn get_src_u8(self) -> u8 {
(self.data & SRC_MASK) as u8
}
#[inline(always)]
pub const fn is_castle(self) -> bool {
(self.data >> 13) == 1
}
#[inline(always)]
pub const fn is_king_castle(self) -> bool {
self.flag() == BitMove::FLAG_KING_CASTLE
}
#[inline(always)]
pub const fn is_queen_castle(self) -> bool {
self.flag() == BitMove::FLAG_QUEEN_CASTLE
}
#[inline(always)]
pub const fn is_en_passant(self) -> bool {
self.flag() == BitMove::FLAG_EP
}
#[inline(always)]
pub fn is_double_push(self) -> (bool, u8) {
let is_double_push: u8 = self.flag() as u8;
match is_double_push {
1 => (true, self.get_dest().0 as u8),
_ => (false, 64),
}
}
#[inline(always)]
pub fn dest_row(self) -> Rank {
self.get_dest().rank()
}
#[inline(always)]
pub fn dest_col(self) -> File {
self.get_dest().file()
}
#[inline(always)]
pub fn src_row(self) -> Rank {
self.get_src().rank()
}
#[inline(always)]
pub fn src_col(self) -> File {
self.get_src().file()
}
#[inline(always)]
pub fn promo_piece(self) -> PieceType {
match (self.flag()) & 0b0011 {
0 => PieceType::N,
1 => PieceType::B,
2 => PieceType::R,
3 | _ => PieceType::Q,
}
}
#[inline(always)]
pub fn move_type(self) -> MoveType {
if self.is_castle() {
return MoveType::Castle;
}
if self.is_promo() {
return MoveType::Promotion;
}
if self.is_en_passant() {
return MoveType::EnPassant;
}
MoveType::Normal
}
pub fn stringify(self) -> String {
let src = self.get_src().to_string();
let dst_sq = self.get_dest();
let dst = if self.is_castle() {
match dst_sq {
SQ::A8 => String::from("c8"),
SQ::A1 => String::from("c1"),
SQ::H8 => String::from("g8"),
SQ::H1 => String::from("g1"),
_ => dst_sq.to_string()
}
} else {
dst_sq.to_string()
};
let mut s = format!("{}{}", src, dst);
if self.is_promo() {
let c = self.promo_piece().char_lower();
s.push(c);
}
s
}
#[inline(always)]
pub const fn get_raw(self) -> u16 {
self.data
}
#[inline(always)]
pub fn incorrect_flag(self) -> bool {
((self.flag()) & 0b1110) == 0b0110
}
#[inline(always)]
pub const fn flag(self) -> u16 {
self.data >> 12
}
#[inline(always)]
pub const fn is_okay(self) -> bool {
self.get_dest_u8() != self.get_src_u8()
}
#[inline(always)]
pub const fn from_to(self) -> u16 {
self.data & FROM_TO_MASK
}
}
#[derive(Eq, Copy, Clone, Debug)]
#[repr(C)]
pub struct ScoringMove {
pub bit_move: BitMove,
pub score: i16
}
impl Default for ScoringMove {
#[inline(always)]
fn default() -> Self {
ScoringMove {
bit_move: BitMove::null(),
score: 0
}
}
}
impl ScoringMove {
#[inline(always)]
pub fn new(m: BitMove) -> Self {
ScoringMove {
bit_move: m,
score: 0
}
}
#[inline(always)]
pub fn new_score(m: BitMove, score: i16) -> Self {
ScoringMove {
bit_move: m,
score,
}
}
#[inline(always)]
pub fn blank(score: i16) -> Self {
ScoringMove {
bit_move: BitMove::null(),
score,
}
}
#[inline(always)]
pub fn bitmove(self) -> BitMove {
self.bit_move
}
#[inline(always)]
pub fn score(self) -> i16 {
self.score
}
#[inline(always)]
pub fn negate(mut self) -> Self {
self.score = self.score.wrapping_neg();
self
}
#[inline(always)]
pub fn swap_move(mut self, mov: BitMove) -> Self {
self.bit_move = mov;
self
}
#[inline(always)]
pub const fn null() -> Self {
ScoringMove {
bit_move: BitMove::null(),
score: 0
}
}
}
impl Ord for ScoringMove {
fn cmp(&self, other: &ScoringMove) -> Ordering {
self.score.cmp(&other.score)
}
}
impl PartialOrd for ScoringMove {
fn partial_cmp(&self, other: &ScoringMove) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for ScoringMove {
fn eq(&self, other: &ScoringMove) -> bool {
self.score == other.score
}
}