use crate::Position;
#[cfg(feature = "compress")]
use core::arch::x86_64::_pext_u64;
#[cfg(feature = "compress")]
#[derive(Copy, Clone)]
struct PawnMoves{
pub norm: u64,
pub capt: u64,
}
#[cfg(feature = "compress")]
impl PawnMoves {
pub fn getmask(&self, from: u64, friends: u64, opp: u64, ep: u64) -> u64{
let mut res: u64 = 0;
let epmask: u64;
if ep == 64 {
epmask = 0;
}else {
epmask = 1_u64 << ep + 8;
}
res |= !(friends | opp) & self.norm;
if from / 8 == 1 {
res |= (res << 8) & !(friends | opp);
}
res |= (opp | epmask) & self.capt;
if from / 8 == 6 {
res |= (res >> 8) | (res >> 16) | (res >> 24);
}
res
}
}
#[cfg(feature = "compress")]
const PAWNMASK: [PawnMoves; 64] = {
let mut res = [PawnMoves{norm:0, capt:0}; 64];
cfor!(let mut sq=8; sq < 56; sq += 1; {
let mut tot = PawnMoves {
norm: 1_u64 << (sq + 8),
capt: 0,
};
if sq%8 != 0 {
tot.capt |= 1_u64 << (sq + 7);
}
if sq%8 != 7 {
tot.capt |= 1_u64 << (sq + 9);
}
res[sq] = tot;
});
res
};
#[cfg(feature = "compress")]
const MOVEMASK: [[u64; 64]; 5] = { let mut res = [[0; 64]; 5];
cfor!(let mut idx=0; idx < 64; idx += 1;{
let x = idx % 8;
let y = idx / 8;
let mut mask: u64 = 0;
cfor!(let mut dx:i32=-2; dx <= 2; dx += 1;{
if dx == 0{
continue
}
cfor!(let mut dy: i32=-2; dy <= 2; dy += 1;{
if dx.abs() + dy.abs() == 3 {
if 0 <= x+dx && x+dx < 8 && 0 <= y+dy && y+dy < 8 {
mask |= 1 << (x+dx) + (y+dy)*8;
}
}
});
});
res[0][idx as usize] = mask;
});
let mut diag: u64 = 0;
let mut idiag: u64 = 0;
let mut diags = [(0, 0); 15];
cfor!(let mut d = 0; d < 15; d += 1; {
diag <<= 8;
idiag <<= 8;
if d < 8 {
diag |= 1 << d;
idiag |= 1 << (7 - d);
}
diags[d] = (diag, idiag);
});
cfor!(let mut sq = 0; sq < 64; sq += 1; {
let col = sq%8;
let row = sq/8;
res[1][sq] = diags[col + row].0 ^ diags[row + 7 - col].1;
});
cfor!(let mut sq = 0; sq < 64; sq += 1; {
let col = 0x0101010101010101_u64 << (sq%8);
let row = 0xff_u64 << (sq/8) * 8;
res[2][sq] = col ^ row;
});
cfor!(let mut sq = 0; sq < 64; sq += 1; {
res[3][sq] = res[1][sq] | res[2][sq];
});
cfor!(let mut idx=0; idx < 64; idx += 1;{
let x = idx % 8;
let y = idx / 8;
let mut mask: u64 = 0;
cfor!(let mut dx:i32=-1; dx <= 1; dx += 1;{
cfor!(let mut dy: i32=-1; dy <= 1; dy += 1;{
if dy != 0 || dx != 0 {
if 0 <= x+dx && x+dx < 8 && 0 <= y+dy && y+dy < 8 {
mask |= 1 << ((x+dx) + (y+dy)*8);
}
}
});
});
res[4][idx as usize] = mask;
});
res
};
#[cfg(feature = "compress")]
pub fn compressmove(pos: &Position, mv: u16) -> (u16, u16) {
if mv == 0 {
return (0, 1);
}
let from = (mv & 0x3f) as u8;
let to = ((mv >> 6) & 0x3f) as u8;
let promo = ((mv >> 12) & 0b11) as u8;
let nb_piece: u16 = pos.bbs[pos.stm as usize].count_ones() as u16;
let id_piece = unsafe { _pext_u64(1_u64 << from as u64, pos.bbs[pos.stm as usize]) }.trailing_zeros() as u16;
let piece = pos.piece(from as usize);
let flag = (mv >> 14) as u8;
if piece.piecetype() == PieceType::Void {
pos.print();
println!("from = {} to = {} piece = {} (piecetype = {}) type = {} promo = {} ep = {}", from, to, piece as u8, piece.piecetype() as u8, flag, promo, pos.ep);
unreachable!();
}
let mut pseudomovemask: u64;
let id_to: u16;
if piece.piecetype() == PieceType::Pawn {
let helper = PAWNMASK[from as usize ^ (56 * pos.stm as usize)];
let opp: u64;
let friends: u64;
if pos.stm {
opp = pos.bbs[0].swap_bytes();
friends = pos.bbs[1].swap_bytes();
} else {
opp = pos.bbs[1];
friends = pos.bbs[0];
}
pseudomovemask = helper.getmask(from as u64 ^ (56 * pos.stm as u64), friends, opp, pos.ep as u64 ^ 56 * (pos.stm && pos.ep != 64) as u64);
if pos.stm {
pseudomovemask = pseudomovemask.swap_bytes();
}
let compact_to: u8;
if pos.stm {
compact_to = to + promo * 8;
} else {
compact_to = to - promo * 8;
}
let movemask = 1_u64 << compact_to as u64;
id_to = unsafe { _pext_u64(movemask, pseudomovemask) }.trailing_zeros() as u16;
}else if piece.piecetype() == PieceType::King {
pseudomovemask = MOVEMASK[4][from as usize] | (pos.castle_mask & (0xff << pos.stm as u64 * 56));
id_to = unsafe { _pext_u64(1_u64 << to as u64, pseudomovemask) }.trailing_zeros() as u16
}else {
pseudomovemask = MOVEMASK[piece.piecetype() as usize - 1][from as usize];
id_to = unsafe { _pext_u64(1_u64 << to as u64, pseudomovemask) }.trailing_zeros() as u16
}
if (id_to as u32) >= pseudomovemask.count_ones() {
pos.print();
println!("from = {} to = {} piece = {} (piecetype = {}) type = {} promo = {} ep = {}", from, to, piece as u8, piece.piecetype() as u8, flag, promo, pos.ep);
println!("{} {} {}", id_to, pseudomovemask.count_ones(), pos.stm);
println!("{:64b}\n{:64b}\n{:64b}", pseudomovemask, 1_u64 << to, pos.castle_mask);
unreachable!()
}
let max = pseudomovemask.count_ones() as u16 * nb_piece;
let val = id_to * nb_piece + id_piece;
(max, val)
}