bulletformat 1.8.0

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

#[repr(C)]
#[derive(Clone, Copy)]
pub struct MarlinFormat {
    occ: u64,
    pcs: [u8; 16],
    stm_enp: u8,
    hfm: u8,
    fmc: u16,
    score: i16,
    result: u8,
    extra: u8,
}

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

pub struct MarlinFormatIter {
    board: MarlinFormat,
    idx: usize,
}

impl Iterator for MarlinFormatIter {
    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 MarlinFormat {
    pub fn occ(&self) -> u64 {
        self.occ
    }

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

    fn res_stm(&self) -> u8 {
        if self.is_black_to_move() {
            2 - self.result
        } else {
            self.result
        }
    }
}

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

    const HEADER_SIZE: usize = 0;

    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.result = (2.0 * result) as u8;
    }
}

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

        let stm = usize::from(mf.stm_enp >> 7);

        if stm == 1 {
            board.score = -mf.score;
            board.result = 2 - mf.result;
        } else {
            board.score = mf.score;
            board.result = mf.result;
        }

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

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

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

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

            if piece & 0b111 == 0b110 {
                piece ^= 0b100;
            }

            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
    }
}