1use crate::{Player, Square, board::Players, finite::Empty as _, square::File};
2
3use File::*;
4
5#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
6pub struct Castles(pub Players<Sides<Option<File>>>);
7
8crate::finite_set!(
9 EnPassant,
11 EnPassantTable {
12 A3 = 0 as a3,
13 B3 = 1 as b3,
14 C3 = 2 as c3,
15 D3 = 3 as d3,
16 E3 = 4 as e3,
17 F3 = 5 as f3,
18 G3 = 6 as g3,
19 H3 = 7 as h3,
20 A6 = 8 as a6,
21 B6 = 9 as b6,
22 C6 = 10 as c6,
23 D6 = 11 as d6,
24 E6 = 12 as e6,
25 F6 = 13 as f6,
26 G6 = 14 as g6,
27 H6 = 15 as h6,
28 }
29);
30
31crate::finite_set!(
47 Side,
49 Sides,
50 SideTable,
51 {
52 King = 0 as king,
53 Queen = 1 as queen,
54 }
55);
56
57impl Castles {
58 #[inline]
59 pub const fn empty() -> Self {
60 Self(Players::EMPTY)
61 }
62
63 #[inline]
64 pub const fn chess() -> Self {
65 use Side::*;
66 let rooks = Sides { queen: Some(Queen.chess_rook()), king: Some(King.chess_rook()) };
67 Self(Players { black: rooks, white: rooks })
68 }
69
70 #[inline]
71 pub const fn chess_compatible(self) -> bool {
72 self.is_subset(Self::chess())
73 }
74
75 #[inline]
76 pub const fn is_subset(self, other: Self) -> bool {
77 const fn file_subset(left: Option<File>, right: Option<File>) -> bool {
79 match (left, right) {
80 (None, _) => true,
81 (Some(left), Some(right)) => left.eq(right),
82 (Some(_), None) => false,
83 }
84 }
85
86 finite_for!(player in Player {
87 finite_for!(side in Side {
88 if !file_subset(self.get(player, side), other.get(player, side)) {
89 return false;
90 }
91 });
92 });
93
94 true
95 }
96
97 #[inline]
98 pub const fn get(self, player: Player, side: Side) -> Option<File> {
99 self.0.get(player).get(side)
100 }
101
102 #[inline]
103 pub const fn has(self, player: Player, side: Side) -> bool {
104 self.get(player, side).is_some()
105 }
106
107 #[inline]
108 pub const fn set(&mut self, player: Player, side: Side, file: File) {
109 *self.0.get_mut(player).get_mut(side) = Some(file);
110 }
111
112 #[inline]
113 pub fn clear(&mut self, player: Player, side: Side) {
114 self.0[player][side] = None;
115 }
116
117 #[inline]
118 pub fn clear_player(&mut self, player: Player) {
119 self.0[player] = Sides::EMPTY;
120 }
121}
122
123impl EnPassant {
124 #[inline]
125 pub const fn from_square(square: Square) -> Option<Self> {
126 use Square::*;
127 Some(match square {
128 A3 => EnPassant::A3,
129 B3 => EnPassant::B3,
130 C3 => EnPassant::C3,
131 D3 => EnPassant::D3,
132 E3 => EnPassant::E3,
133 F3 => EnPassant::F3,
134 G3 => EnPassant::G3,
135 H3 => EnPassant::H3,
136 A6 => EnPassant::A6,
137 B6 => EnPassant::B6,
138 C6 => EnPassant::C6,
139 D6 => EnPassant::D6,
140 E6 => EnPassant::E6,
141 F6 => EnPassant::F6,
142 G6 => EnPassant::G6,
143 H6 => EnPassant::H6,
144 _ => return None,
145 })
146 }
147
148 #[inline]
149 pub const fn square(self) -> Square {
150 use EnPassant::*;
151 match self {
152 A3 => Square::A3,
153 B3 => Square::B3,
154 C3 => Square::C3,
155 D3 => Square::D3,
156 E3 => Square::E3,
157 F3 => Square::F3,
158 G3 => Square::G3,
159 H3 => Square::H3,
160 A6 => Square::A6,
161 B6 => Square::B6,
162 C6 => Square::C6,
163 D6 => Square::D6,
164 E6 => Square::E6,
165 F6 => Square::F6,
166 G6 => Square::G6,
167 H6 => Square::H6,
168 }
169 }
170}
171
172impl Side {
173 #[inline]
174 pub const fn chess_rook(self) -> File {
175 match self {
176 Side::King => H,
177 Side::Queen => A,
178 }
179 }
180
181 #[inline]
182 pub const fn of_rook(king: Square, rook: File) -> Self {
183 use Side::*;
184 if king.file().index() <= rook.index() { King } else { Queen }
185 }
186
187 #[inline]
189 pub const fn king_to_file(self) -> File {
190 use Side::*;
191 match self {
192 King => G,
193 Queen => C,
194 }
195 }
196
197 #[inline]
199 pub const fn rook_to_file(self) -> File {
200 use Side::*;
201 match self {
202 King => F,
203 Queen => D,
204 }
205 }
206}
207
208impl TryFrom<Square> for EnPassant {
209 type Error = ();
210
211 fn try_from(square: Square) -> Result<Self, ()> {
212 Self::from_square(square).ok_or(())
213 }
214}
215
216impl From<EnPassant> for Square {
217 fn from(en_passant: EnPassant) -> Self {
218 en_passant.square()
219 }
220}