1use crate::{BitBoard, Side, Square};
2use anyhow::{anyhow, Error, Result};
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5use enumset::EnumSetType;
6
7mod kings;
8mod knights;
9mod pawns;
10mod sliding;
11
12#[derive(Debug, EnumSetType, Ord, PartialOrd, Hash)]
15#[rustfmt::skip]
16pub enum Piece {
17 WP, WN, WB, WR, WQ, WK,
18 BP, BN, BB, BR, BQ, BK,
19}
20
21impl Display for Piece {
22 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23 write!(f, "{}", format!("{:?}", self).to_lowercase())
24 }
25}
26
27impl FromStr for Piece {
28 type Err = Error;
29
30 fn from_str(s: &str) -> Result<Self, Self::Err> {
31 let lower = s.to_lowercase();
32 Piece::all()
33 .find(|p| p.to_string() == lower)
34 .ok_or(anyhow!("Cannot parse {} as piece", s))
35 }
36}
37
38impl Piece {
39 pub fn all() -> impl Iterator<Item = Piece> {
41 ALL.iter().cloned()
42 }
43
44 pub fn whites() -> impl Iterator<Item = Piece> {
46 WHITE.iter().cloned()
47 }
48
49 pub fn blacks() -> impl Iterator<Item = Piece> {
51 BLACK.iter().cloned()
52 }
53
54 pub fn king(side: Side) -> Piece {
56 match side {
57 Side::White => Piece::WK,
58 Side::Black => Piece::BK,
59 }
60 }
61
62 pub fn queen(side: Side) -> Piece {
64 match side {
65 Side::White => Piece::WQ,
66 Side::Black => Piece::BQ,
67 }
68 }
69
70 pub fn rook(side: Side) -> Piece {
72 match side {
73 Side::White => Piece::WR,
74 Side::Black => Piece::BR,
75 }
76 }
77
78 pub fn pawn(side: Side) -> Piece {
80 match side {
81 Side::White => Piece::WP,
82 Side::Black => Piece::BP,
83 }
84 }
85
86 pub fn of(side: Side) -> impl Iterator<Item = Piece> {
88 match side {
89 Side::White => (&WHITE).iter().cloned(),
90 Side::Black => (&BLACK).iter().cloned(),
91 }
92 }
93
94 pub fn side(self) -> Side {
96 if (self as u8) < 6 {
97 Side::White
98 } else {
99 Side::Black
100 }
101 }
102
103 pub fn is_pawn(self) -> bool {
105 (self as u8) % 6 == 0
106 }
107
108 pub fn is_knight(self) -> bool {
110 (self as u8) % 6 == 1
111 }
112
113 pub fn control(self, loc: Square, whites: BitBoard, blacks: BitBoard) -> BitBoard {
116 Piece::CONTROL_FN[self as usize](loc, whites, blacks)
117 }
118
119 pub fn empty_control(self, loc: Square) -> BitBoard {
122 self.control(loc, BitBoard::EMPTY, BitBoard::EMPTY)
123 }
124
125 pub fn moves(self, loc: Square, whites: BitBoard, blacks: BitBoard) -> BitBoard {
131 Piece::MOVE_FN[self as usize](loc, whites, blacks)
132 }
133
134 const CONTROL_FN: [fn(Square, BitBoard, BitBoard) -> BitBoard; 12] = [
135 pawns::white_control,
136 knights::control,
137 sliding::bishops::control,
138 sliding::rooks::control,
139 sliding::queens::control,
140 kings::control,
141 pawns::black_control,
142 knights::control,
143 sliding::bishops::control,
144 sliding::rooks::control,
145 sliding::queens::control,
146 kings::control,
147 ];
148
149 const MOVE_FN: [fn(Square, BitBoard, BitBoard) -> BitBoard; 12] = [
150 pawns::white_moves,
151 knights::white_moves,
152 sliding::bishops::white_moves,
153 sliding::rooks::white_moves,
154 sliding::queens::white_moves,
155 kings::white_moves,
156 pawns::black_moves,
157 knights::black_moves,
158 sliding::bishops::black_moves,
159 sliding::rooks::black_moves,
160 sliding::queens::black_moves,
161 kings::black_moves,
162 ];
163}
164
165const ALL: [Piece; 12] = [
167 Piece::WP,
168 Piece::WN,
169 Piece::WB,
170 Piece::WR,
171 Piece::WQ,
172 Piece::WK,
173 Piece::BP,
174 Piece::BN,
175 Piece::BB,
176 Piece::BR,
177 Piece::BQ,
178 Piece::BK,
179];
180
181const WHITE: [Piece; 6] = [
182 Piece::WP,
183 Piece::WN,
184 Piece::WB,
185 Piece::WR,
186 Piece::WQ,
187 Piece::WK,
188];
189
190const BLACK: [Piece; 6] = [
191 Piece::BP,
192 Piece::BN,
193 Piece::BB,
194 Piece::BR,
195 Piece::BQ,
196 Piece::BK,
197];
198
199#[cfg(test)]
200mod test {
201 use crate::Piece;
202
203 #[test]
204 fn display() {
205 assert_eq!("wp", Piece::WP.to_string().as_str());
206 assert_eq!("br", Piece::BR.to_string().as_str());
207 }
208
209 #[test]
210 fn from_str() {
211 assert_eq!(Piece::WP, "wp".parse::<Piece>().unwrap());
212 assert_eq!(Piece::WP, "WP".parse::<Piece>().unwrap());
213 assert_eq!(Piece::BQ, "bq".parse::<Piece>().unwrap());
214 assert!("ba".parse::<Piece>().is_err());
215 assert!("bqs".parse::<Piece>().is_err());
216 assert!("wxk".parse::<Piece>().is_err());
217 }
218}