1use chess::{Board, ChessMove, Piece, Square};
2
3use crate::{
4 bitbuffer::BitBuffer,
5 filters::{diagonal::Diagonal, knight::Knight, straight::Straight, Filter},
6 outcome::Outcome,
7 PROMOTION_KEY,
8};
9
10#[derive(Clone)]
11pub struct Reader {
12 data: Vec<u8>,
13 chess: Board,
14 bit_buffer: BitBuffer,
15 outcome: Option<Outcome>,
16}
17
18impl Reader {
19 pub fn new(data: &[u8]) -> Self {
22 Reader {
23 data: data.to_vec(),
24 chess: Board::default(),
25 bit_buffer: BitBuffer::from_bytes(data),
26 outcome: None,
27 }
28 }
29
30 pub fn get_outcome(&self) -> &Option<Outcome> {
31 &self.outcome
32 }
33}
34
35fn safe_get_square(index: u8) -> Square {
36 assert!((0..64).contains(&index));
37
38 unsafe { Square::new(index) }
39}
40
41impl Iterator for Reader {
42 fn next(&mut self) -> Option<Self::Item> {
44 let to = safe_get_square(self.data[0] & 0b00111111);
45 let id = self.data[0] >> 6;
46
47 let (square_data, overflow_length) = match id {
48 3 => (Straight::get_square_data(&to, &self.chess), 2),
49 2 => (Diagonal::get_square_data(&to, &self.chess), 2),
50 1 => (Knight::get_square_data(&to, &self.chess), 3),
51 0 => {
52 self.outcome = Some(Outcome::from_id(self.data[0]));
53 return None;
54 }
55 _ => panic!("Unknown filter"),
56 };
57
58 self.data.remove(0);
59
60 let index;
61
62 if square_data.iter().filter(|square| square.is_some()).count() == 1 {
63 index = square_data
64 .iter()
65 .position(|square| square.is_some())
66 .expect("Could not find previously found valid move (radioactive particle?)");
67 } else {
68 index = self.bit_buffer.read(overflow_length) as usize;
69 }
70
71 let from = square_data[index].expect("Could not find valid move from overflow index");
72
73 let from_piece = self
74 .chess
75 .piece_on(from)
76 .expect("Could not find piece at previously validated square (radioactive particle?)");
77
78 let chess_move = ChessMove::new(
79 from,
80 to,
81 if from_piece == Piece::Pawn
82 && self.chess.color_on(from).unwrap().to_their_backrank() == to.get_rank()
83 {
84 Some(PROMOTION_KEY[self.bit_buffer.read(2) as usize])
85 } else {
86 None
87 },
88 );
89
90 self.chess.clone().make_move(chess_move, &mut self.chess);
91
92 Some((chess_move, self.chess.clone()))
93 }
94
95 type Item = (ChessMove, Board);
96}