ascn_rs/
reader.rs

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    /// Creates a new reader based on the buffer provided
20    /// It also creates a new default chess board
21    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    /// Returns the next move processed and the current state of the board after the move has been applied
43    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}