syd-format 0.1.0

binary format for chess game tree
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] = { // for knight to king (king withoyut castling moves)
    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)
}