1use crate::position::{
2 PieceType, Pieces, Position
3};
4use crate::filter::Filter;
5#[cfg(feature = "readerstats")]
6use crate::stats::ReaderStat;
7#[cfg(feature = "positionstats")]
8use crate::stats::Stats;
9use std::io::{Cursor, Read};
10use bulletformat::ChessBoard;
11
12pub struct SydGame{
13 #[cfg(feature = "readerstats")]
14 pub readerstat: ReaderStat,
15 #[cfg(feature = "positionstats")]
16 pub posstats: Stats,
17 #[cfg(feature = "compress")]
18 last_score: i16,
19}
20impl SydGame {
21 pub fn new() -> Self{
22 Self{
23 #[cfg(feature = "readerstats")]
24 readerstat:ReaderStat::new(),
25 #[cfg(feature = "positionstats")]
26 posstats:Stats::new(),
27 #[cfg(feature = "compress")]
28 last_score: 0,
29 }
30 }
31 pub fn parse_tree<R: std::io::Read>(&mut self, cursor: &mut R, out: &mut Vec<ChessBoard>, pos:&mut Position, filter: &Filter){
32 let mut buff: [u8; 2] = [0; 2];
33
34 cursor.read_exact(&mut buff).unwrap();
35 let bm: u16 = u16::from_le_bytes(buff);
36
37 cursor.read_exact(&mut buff).unwrap();
38 let score: i16 = i16::from_le_bytes(buff);
39
40 cursor.read_exact(&mut buff).unwrap();
41 let info = buff[0];
42 let nb_child = buff[1];
43
44 pos.bm = bm;
45 pos.bound = info%3;
46 pos.depth = info/3;
47 pos.score = score;
48
49 #[cfg(feature = "compress")]
50 let sizescorediff = ((pos.score as i64 - self.last_score as i64).abs() as u64).next_power_of_two().ilog2() as u64 + 1;
51
52 if !filter.should_filter(pos) {
53 #[cfg(feature = "positionstats")]
54 self.posstats.update(pos);
55 out.push(pos.tobullet());
56 }
57 #[cfg(feature = "readerstats")]
58 let mut is_bm_continued = false;
59 for _id_child in 0..nb_child {
60 cursor.read_exact(&mut buff).unwrap();
61 let mv: u16 = u16::from_le_bytes(buff);
62 #[cfg(feature = "readerstats")]
63 if mv == bm {
64 is_bm_continued = true;
65 }
66 let mut newpos: Position = *pos;
67
68 newpos.play(mv);
69 #[cfg(feature = "compress")]
70 {
71 self.last_score = -pos.score;
72 }
73 self.parse_tree(cursor, out, &mut newpos, filter);
74 }
75 #[cfg(feature = "compress")]
76 {
77 let size_move: u64 =
78 17 + 5 + 9 * !is_bm_continued as u64 + sizescorediff + ((nb_child.max(2) as u64 - 2).next_power_of_two().ilog2() as u64+3) * (nb_child > 1) as u64; self.readerstat.update(nb_child as usize, is_bm_continued, size_move);
84 }
85 #[cfg(all(not(feature = "compress"), feature = "readerstats"))]
86 {
87 self.readerstat.update(nb_child as usize, is_bm_continued, 0);
88 }
89 }
90
91 pub fn parse_syd<R: std::io::Read>(&mut self, reader: &mut R, res: &mut Vec<ChessBoard>, filter: &Filter) -> std::io::Result<()>{
92
93 #[cfg(feature = "compress")]
94 {
95 self.last_score = 0;
96 }
97
98 let mut buff_4: [u8; 4] = [0; 4];
99 reader.read_exact(&mut buff_4)?;
100 let size:u32 = u32::from_le_bytes(buff_4);
101 let mut full = Vec::<u8>::new();
102 full.resize(size as usize, 0);
103 assert!(full.len() == size as usize);
104 reader.read_exact(&mut full).unwrap();
105
106 let mut c = Cursor::new(full);
107 let mut marlin: [u8; 32] = [0; 32];
108 c.read_exact(&mut marlin).unwrap();
109
110 let mut startpos: Position = Position::default();
111 let occupancy = u64::from_le_bytes(marlin[..8].try_into().unwrap());
112 let mut mask = occupancy;
113 for id_piece in 0..occupancy.count_ones() {
114 let pos = mask.trailing_zeros();
115 let mut piece = Pieces::from_viri((marlin[(8+id_piece/2) as usize] >> 4 * (id_piece%2)) & 0b1111);
116 if piece.piecetype() == PieceType::Castle {
118 startpos.update_castle_rights(pos as usize);
119 piece = Pieces::from_pc_color(PieceType::Rook, piece.color());
120 }
121 startpos.push(pos, piece);
122
123 mask &= mask - 1;
124 }
125 let stmep = marlin[24];
126 let mut epsquare = stmep & 0b1111111;
127 let stm: bool = (stmep >> 7) != 0;
128 if epsquare != 64 {
129 if stm {
130 epsquare += 8;
131 } else {
132 epsquare -= 8;
133 }
134 }
135 startpos.update_ep(epsquare as usize);
136 startpos.update_stm(stm as usize);
137 startpos.rule50 = marlin[25];
138 self.parse_tree(&mut c, res, &mut startpos, filter);
139
140 Ok(())
141 }
142}