1use core::num::NonZeroU32;
4
5use crate::{
6 Player,
7 board::{PlayerTable, Role, RoleTable},
8 formats::prelude::Framed,
9 position::SideTable,
10 square::{File, Square},
11};
12
13pub mod convert;
14pub mod parse;
15
16pub use parse::{PERMUTE, game, game_with_info, header, info, mode, position, tokens};
17
18pub const SUFFIX: &str = "cbg";
20
21#[derive(Clone, Debug)]
22pub struct Game {
23 pub position: Position,
24 pub tokens: Vec<Token>,
25}
26
27#[derive(Clone, Debug)]
28pub struct Position {
29 pub pieces: Pieces,
30 pub turn: Player,
31 pub castles: Castles,
32 pub en_passant: Option<File>,
33 pub round: NonZeroU32,
34}
35
36#[derive(Clone, Copy, Debug)]
38pub enum Token {
39 Pop,
40 Push,
41 Move(Move),
42 Skip,
43}
44
45#[derive(Clone, Copy, Debug)]
46pub enum Move {
47 Null,
48 King(i8, i8),
50 Castle(i8),
52 Queen(u8, u8, u8),
54 Rook(u8, u8, u8),
56 Bishop(u8, u8, u8),
58 Knight(u8, i8, i8),
60 Pawn(File, PawnMove),
62 FromTo(Square, Square, Role),
72}
73
74#[repr(u8)]
75#[derive(Clone, Copy, Debug)]
76pub enum PawnMove {
77 One,
78 Two,
79 Left,
81 Right,
82}
83
84pub type Castles = PlayerTable<SideTable<bool>>;
85
86pub type Pieces = PlayerTable<RoleTable<[Option<Square>; 10]>>;
88
89impl Pieces {
90 pub fn standard() -> Self {
91 use Player::*;
92 use Role::*;
93 use Square::*;
94
95 let mut pieces = Self::empty();
96 pieces[White][King][0] = Some(E1);
97 pieces[White][Queen][0] = Some(D1);
98 pieces[White][Rook][..2].copy_from_slice(&[Some(A1), Some(H1)]);
99 pieces[White][Bishop][..2].copy_from_slice(&[Some(C1), Some(F1)]);
100 pieces[White][Knight][..2].copy_from_slice(&[Some(B1), Some(G1)]);
101 pieces[White][Pawn][..8].copy_from_slice(&[
102 Some(A2),
103 Some(B2),
104 Some(C2),
105 Some(D2),
106 Some(E2),
107 Some(F2),
108 Some(G2),
109 Some(H2),
110 ]);
111 pieces[Black][King][0] = Some(E8);
112 pieces[Black][Queen][0] = Some(D8);
113 pieces[Black][Rook][..2].copy_from_slice(&[Some(A8), Some(H8)]);
114 pieces[Black][Bishop][..2].copy_from_slice(&[Some(C8), Some(F8)]);
115 pieces[Black][Knight][..2].copy_from_slice(&[Some(B8), Some(G8)]);
116 pieces[Black][Pawn][..8].copy_from_slice(&[
117 Some(A7),
118 Some(B7),
119 Some(C7),
120 Some(D7),
121 Some(E7),
122 Some(F7),
123 Some(G7),
124 Some(H7),
125 ]);
126 pieces
127 }
128}
129
130#[derive(Clone, Copy, Debug)]
131pub struct Header {
132 pub first_game: u16,
133 pub len: u32,
134}
135
136impl Header {
137 pub const LEN: usize = 26;
138}
139
140#[derive(Clone, Copy, Debug)]
141pub struct Info {
142 pub len: usize,
144 pub mode: Mode,
145}
146
147impl Info {
148 pub const LEN: usize = 4;
149}
150
151impl Framed for Info {
152 const LEN: usize = Info::LEN;
153
154 fn total(&self) -> usize {
155 Self::LEN + self.len
156 }
157}
158
159#[repr(transparent)]
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub struct Mode(pub u8);
162
163impl Mode {
164 #[inline]
165 pub const fn is_freestyle(self) -> bool {
166 self.0 & ((1 << 1) | (1 << 3)) != 0
168 }
169
170 #[inline]
171 pub const fn has_special_encoding(self) -> bool {
172 self.0 & (1 << 2) != 0
173 }
174
175 #[inline]
176 pub const fn has_setup(self) -> bool {
177 self.0 & (1 << 6) != 0
178 }
179
180 #[inline]
181 pub const fn is_undecodable(self) -> bool {
182 self.0 & (1 << 7) != 0
183 }
184}