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
102 res.reserve_exact((size as usize-38)/8+1);
103
104 let mut full = Vec::<u8>::new();
105 full.resize(size as usize, 0);
106 assert!(full.len() == size as usize);
107 reader.read_exact(&mut full).unwrap();
108
109 let mut c = Cursor::new(full);
110 let mut marlin: [u8; 32] = [0; 32];
111 c.read_exact(&mut marlin).unwrap();
112
113 let mut startpos: Position = Position::default();
114 let occupancy = u64::from_le_bytes(marlin[..8].try_into().unwrap());
115 let mut mask = occupancy;
116 for id_piece in 0..occupancy.count_ones() {
117 let pos = mask.trailing_zeros();
118 let mut piece = Pieces::from_viri((marlin[(8+id_piece/2) as usize] >> 4 * (id_piece%2)) & 0b1111);
119 if piece.piecetype() == PieceType::Castle {
121 startpos.update_castle_rights(pos as usize);
122 piece = Pieces::from_pc_color(PieceType::Rook, piece.color());
123 }
124 startpos.push(pos, piece);
125
126 mask &= mask - 1;
127 }
128 let stmep = marlin[24];
129 let mut epsquare = stmep & 0b1111111;
130 let stm: bool = (stmep >> 7) != 0;
131 if epsquare != 64 {
132 if stm {
133 epsquare += 8;
134 } else {
135 epsquare -= 8;
136 }
137 }
138 startpos.update_ep(epsquare as usize);
139 startpos.update_stm(stm as usize);
140 startpos.rule50 = marlin[25];
141 self.parse_tree(&mut c, res, &mut startpos, filter);
142
143 Ok(())
144 }
145}