syd-format 0.2.1

binary format for chess game tree
Documentation
use crate::position::{
    PieceType, Pieces, Position
};
use crate::filter::Filter;
#[cfg(feature = "readerstats")]
use crate::stats::ReaderStat;
#[cfg(feature = "positionstats")]
use crate::stats::Stats;
use std::io::{Cursor, Read};
use bulletformat::ChessBoard;

pub struct SydGame{
    #[cfg(feature = "readerstats")]
    pub readerstat: ReaderStat,
    #[cfg(feature = "positionstats")]
    pub posstats: Stats,
    #[cfg(feature = "compress")]
    last_score: i16,
}
impl SydGame {
    pub fn new() -> Self{
        Self{
            #[cfg(feature = "readerstats")]
            readerstat:ReaderStat::new(),
            #[cfg(feature = "positionstats")]
            posstats:Stats::new(),
            #[cfg(feature = "compress")]
            last_score: 0,
        }
    }
    pub fn parse_tree<R: std::io::Read>(&mut self, cursor: &mut R, out: &mut Vec<ChessBoard>, pos:&mut Position, filter: &Filter){
        let mut buff: [u8; 2] = [0; 2];

        cursor.read_exact(&mut buff).unwrap();
        let bm: u16 = u16::from_le_bytes(buff);

        cursor.read_exact(&mut buff).unwrap();
        let score: i16 = i16::from_le_bytes(buff);

        cursor.read_exact(&mut buff).unwrap();
        let info = buff[0];
        let nb_child = buff[1];

        pos.bm = bm;
        pos.bound = info%3;
        pos.depth = info/3;
        pos.score = score;

        #[cfg(feature = "compress")]
        let sizescorediff = ((pos.score as i64 - self.last_score as i64).abs() as u64).next_power_of_two().ilog2() as u64 + 1;

        if !filter.should_filter(pos) {
            #[cfg(feature = "positionstats")]
            self.posstats.update(pos);
            out.push(pos.tobullet());
        }
        #[cfg(feature = "readerstats")]
        let mut is_bm_continued = false;
        for _id_child in 0..nb_child {
            cursor.read_exact(&mut buff).unwrap();
            let mv: u16 = u16::from_le_bytes(buff);
            #[cfg(feature = "readerstats")]
            if mv == bm {
                is_bm_continued = true;
            }
            let mut newpos: Position = *pos;
            
            newpos.play(mv);
            #[cfg(feature = "compress")]
            {
            self.last_score = -pos.score;
            }
            self.parse_tree(cursor, out, &mut newpos, filter);
        }
        #[cfg(feature = "compress")]
        {
        let size_move: u64 =
            17 +                                                    // bound + branch + move to get this position
            5 +                             // depth
            9 * !is_bm_continued as u64 + // bm of the position
            sizescorediff +  // score
            ((nb_child.max(2) as u64 - 2).next_power_of_two().ilog2() as u64+3) * (nb_child > 1) as u64;      // number of childs
        self.readerstat.update(nb_child as usize, is_bm_continued, size_move);
        }
        #[cfg(all(not(feature = "compress"), feature = "readerstats"))]
        {
            self.readerstat.update(nb_child as usize, is_bm_continued, 0);
        }
    }

    pub fn parse_syd<R: std::io::Read>(&mut self, reader: &mut R, res: &mut Vec<ChessBoard>, filter: &Filter) -> std::io::Result<()>{

        #[cfg(feature = "compress")]
        {
            self.last_score = 0;
        }

        let mut buff_4: [u8; 4] = [0; 4];
        reader.read_exact(&mut buff_4)?;
        let size:u32 = u32::from_le_bytes(buff_4);

        res.reserve_exact((size as usize-38)/8+1);

        let mut full = Vec::<u8>::new();
        full.resize(size as usize, 0);
        assert!(full.len() == size as usize);
        reader.read_exact(&mut full).unwrap();

        let mut c = Cursor::new(full);
        let mut marlin: [u8; 32] = [0; 32];
        c.read_exact(&mut marlin).unwrap();
        
        let mut startpos: Position = Position::default();
        let occupancy = u64::from_le_bytes(marlin[..8].try_into().unwrap());
        let mut mask = occupancy;
        for id_piece in 0..occupancy.count_ones() {
            let pos = mask.trailing_zeros();
            let mut piece = Pieces::from_viri((marlin[(8+id_piece/2) as usize] >> 4 * (id_piece%2)) & 0b1111);
            //println!("piece={}", piece);
            if piece.piecetype() == PieceType::Castle {
                startpos.update_castle_rights(pos as usize);
                piece = Pieces::from_pc_color(PieceType::Rook, piece.color());
            }
            startpos.push(pos, piece);

            mask &= mask - 1;
        }
        let stmep = marlin[24];
        let mut epsquare = stmep & 0b1111111;
        let stm: bool = (stmep >> 7) != 0;
        if epsquare != 64 {
            if stm {
                epsquare += 8;
            } else {
                epsquare -= 8;
            }
        }
        startpos.update_ep(epsquare as usize);
        startpos.update_stm(stm as usize);
        startpos.rule50 = marlin[25];
        self.parse_tree(&mut c, res, &mut startpos, filter);

        Ok(())
    }
}