1use crate::side::Side;
2use std::fmt;
3
4type PieceInternal = u8;
5
6#[derive(PartialEq, PartialOrd, Copy, Clone)]
8pub struct Piece(PieceInternal);
9
10const CHARS: [char; 12] = ['B', 'b', 'Q', 'q', 'R', 'r', 'N', 'n', 'P', 'p', 'K', 'k'];
11const NAMES: [&str; 12] = [
15 "white bishop",
16 "black bishop",
17 "white queen",
18 "black queen",
19 "white rook",
20 "black rook",
21 "white knight",
22 "black knight",
23 "white pawn",
24 "black pawn",
25 "white king",
26 "black king",
27];
28
29#[derive(PartialEq, PartialOrd, Copy, Clone)]
31pub struct Kind(pub PieceInternal);
32
33impl Kind {
34 pub fn pc(self, side: Side) -> Piece {
35 Piece((self.0 << 1) | side.raw() as PieceInternal)
36 }
37
38 pub fn to_usize(self) -> usize {
39 self.0 as usize
40 }
41
42 pub const fn to_u8(self) -> u8 {
43 self.0 as u8
44 }
45
46 pub fn to_char(self) -> char {
47 CHARS[self.to_usize() << 1]
48 }
49
50 pub fn iter() -> KindsIter {
51 KindsIter(Kind(0))
52 }
53
54 pub fn to_string(self) -> &'static str {
55 KIND_NAMES[self.to_usize()]
56 }
57
58 pub fn string_plural(self) -> String {
59 KIND_NAMES[self.to_usize()].to_string() + "s"
60 }
61}
62
63const KIND_NAMES: [&str; 6] = ["bishop", "queen", "rook", "knight", "pawn", "king"];
64
65#[derive(Debug)]
66pub struct KindsIter(Kind);
67
68impl Iterator for KindsIter {
69 type Item = Kind;
70
71 fn next(&mut self) -> Option<Kind> {
72 let kd = self.0;
73
74 if kd >= NULL_KIND {
75 return None;
76 }
77
78 (self.0).0 += 1;
79
80 Some(kd)
81 }
82}
83
84impl fmt::Debug for Kind {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 write!(f, "{}", self.to_char())
87 }
88}
89
90impl fmt::Display for Kind {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 write!(f, "{}", self.to_char())
93 }
94}
95
96#[allow(dead_code)]
97pub const BISHOP: Kind = Kind(0);
98#[allow(dead_code)]
99pub const QUEEN: Kind = Kind(1);
100#[allow(dead_code)]
101pub const ROOK: Kind = Kind(2);
102#[allow(dead_code)]
103pub const KNIGHT: Kind = Kind(3);
104#[allow(dead_code)]
105pub const PAWN: Kind = Kind(4);
106#[allow(dead_code)]
107pub const KING: Kind = Kind(5);
108#[allow(dead_code)]
109pub const NULL_KIND: Kind = Kind(6);
110
111#[allow(dead_code)]
112pub const WHITE_BISHOP: Piece = Piece(0);
113#[allow(dead_code)]
114pub const BLACK_BISHOP: Piece = Piece(1);
115
116#[allow(dead_code)]
117pub const WHITE_QUEEN: Piece = Piece(2);
118#[allow(dead_code)]
119pub const BLACK_QUEEN: Piece = Piece(3);
120
121#[allow(dead_code)]
122pub const WHITE_ROOK: Piece = Piece(4);
123#[allow(dead_code)]
124pub const BLACK_ROOK: Piece = Piece(5);
125
126#[allow(dead_code)]
127pub const WHITE_KNIGHT: Piece = Piece(6);
128#[allow(dead_code)]
129pub const BLACK_KNIGHT: Piece = Piece(7);
130
131#[allow(dead_code)]
132pub const WHITE_PAWN: Piece = Piece(8);
133#[allow(dead_code)]
134pub const BLACK_PAWN: Piece = Piece(9);
135
136#[allow(dead_code)]
137pub const WHITE_KING: Piece = Piece(10);
138#[allow(dead_code)]
139pub const BLACK_KING: Piece = Piece(11);
140
141#[allow(dead_code)]
142pub const NULL_PIECE: Piece = Piece(12);
143
144impl Piece {
145 pub fn to_usize(&self) -> usize {
146 self.0 as usize
147 }
148
149 pub fn to_char(&self) -> char {
150 CHARS[self.to_usize()]
151 }
152
153 pub fn kind(&self) -> Kind {
154 Kind(self.0 >> 1)
155 }
156
157 pub fn is_none(&self) -> bool {
158 *self == NULL_PIECE
159 }
160
161 pub fn is_some(&self) -> bool {
162 *self != NULL_PIECE
163 }
164
165 pub fn is_slider(&self) -> bool {
167 debug_assert!(self.is_some());
168 self.0 <= BLACK_ROOK.0
169 }
170
171 pub fn to_string(&self) -> &'static str {
172 NAMES[self.to_usize()]
173 }
174
175 pub fn string_plural(&self) -> String {
176 NAMES[self.to_usize()].to_string() + "s"
177 }
178
179 pub fn side(&self) -> Side {
180 Side(self.to_usize() & 1)
181 }
182
183 pub fn iter() -> PiecesIter {
184 PiecesIter(Piece(0))
185 }
186
187 pub fn parse(chr: char) -> Result<Piece, String> {
188 for pc in Piece::iter() {
189 if pc.to_char() == chr {
190 return Ok(pc);
191 }
192 }
193 Err(format!("Invalid piece: {}", chr))
194 }
195}
196
197#[derive(Debug)]
198pub struct PiecesIter(Piece);
199
200impl Iterator for PiecesIter {
201 type Item = Piece;
202
203 fn next(&mut self) -> Option<Piece> {
204 let pc = self.0;
205
206 if pc >= NULL_PIECE {
207 return None;
208 }
209
210 (self.0).0 += 1;
211
212 Some(pc)
213 }
214}
215
216impl fmt::Display for Piece {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 write!(f, "{}", self.to_char())
219 }
220}
221
222impl fmt::Debug for Piece {
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 write!(f, "{}", self.to_char())
225 }
226}
227
228#[cfg(test)]
229mod test {
230 use super::*;
231 use crate::side::{BLACK, WHITE};
232
233 #[test]
234 fn to_char() {
235 assert_eq!(BLACK_ROOK.to_char(), 'r');
236 assert_eq!(WHITE_KING.to_char(), 'K');
237 }
238
239 #[test]
240 fn side() {
241 assert_eq!(WHITE_PAWN.side(), WHITE);
242 assert_eq!(BLACK_KNIGHT.side(), BLACK);
243 }
244
245 #[test]
246 fn to_usize() {
247 assert_eq!(BLACK_ROOK.to_usize(), 5);
248 assert_eq!(WHITE_KING.to_usize(), 10);
249 }
250
251 #[test]
252 fn kind() {
253 assert_eq!(WHITE_PAWN.kind(), PAWN);
254 assert_eq!(BLACK_KING.kind(), KING);
255 }
256}