bulletformat 1.8.0

Binary Data Formats, Data Loader and Utilities for bullet.
Documentation
use crate::{BulletFormat, ChessBoard};

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct CudADFormat {
    pcs: [u8; 16],
    occ: u64,
    mvcnt: u8,
    fmr: u8,
    stmr: u8,
    enp: u8,
    score: i16,
    wdl: i8,
}

impl IntoIterator for CudADFormat {
    type Item = (u8, u8);
    type IntoIter = CudADFormatIter;
    fn into_iter(self) -> Self::IntoIter {
        CudADFormatIter {
            board: self,
            idx: 0,
        }
    }
}

pub struct CudADFormatIter {
    board: CudADFormat,
    idx: usize,
}

impl Iterator for CudADFormatIter {
    type Item = (u8, u8);
    fn next(&mut self) -> Option<Self::Item> {
        if self.board.occ == 0 {
            return None;
        }

        let square = self.board.occ.trailing_zeros() as u8;
        let piece = (self.board.pcs[self.idx / 2] >> (4 * (self.idx & 1))) & 0b1111;

        self.board.occ &= self.board.occ - 1;
        self.idx += 1;

        Some((piece, square))
    }
}

impl CudADFormat {
    pub fn occ(&self) -> u64 {
        self.occ
    }

    fn is_black_to_move(&self) -> bool {
        self.stmr >> 7 > 0
    }

    fn res_stm(&self) -> u8 {
        let r = if self.is_black_to_move() {
            1 - self.wdl
        } else {
            1 + self.wdl
        };

        assert!(r >= 0);

        r as u8
    }
}

impl BulletFormat for CudADFormat {
    type FeatureType = (u8, u8);

    const HEADER_SIZE: usize = 1288;

    fn score(&self) -> i16 {
        if self.is_black_to_move() {
            -self.score
        } else {
            self.score
        }
    }

    fn result(&self) -> f32 {
        f32::from(self.res_stm()) / 2.
    }

    fn result_idx(&self) -> usize {
        usize::from(self.res_stm())
    }

    fn set_result(&mut self, result: f32) {
        self.wdl = (2.0 * result - 1.0) as i8;
    }
}

impl From<CudADFormat> for ChessBoard {
    fn from(cudad: CudADFormat) -> Self {
        let mut board = Self::default();

        let stm = cudad.is_black_to_move();

        if stm {
            board.score = -cudad.score;
        } else {
            board.score = cudad.score;
        }

        board.result = cudad.res_stm();

        let mut features = [(0, 0); 32];
        let mut fidx = 0;

        for (mut piece, mut square) in cudad.into_iter() {
            if stm {
                piece ^= 8;
                square ^= 56;
            }

            if piece == 5 {
                board.ksq = square;
            }

            if piece == 13 {
                board.opp_ksq = square ^ 56;
            }

            features[fidx] = (piece, square);
            fidx += 1;
        }

        features[..fidx].sort_by_key(|feat| feat.1);

        for (idx, (piece, square)) in features.iter().enumerate().take(fidx) {
            board.occ |= 1 << square;
            board.pcs[idx / 2] |= piece << (4 * (idx & 1));
        }

        board
    }
}