1use super::{Board, Color, Move, Position};
2use alloc::vec::Vec;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
14pub enum Piece {
15 King(Color, Position),
16 Queen(Color, Position),
17 Rook(Color, Position),
18 Bishop(Color, Position),
19 Knight(Color, Position),
20 Pawn(Color, Position),
21}
22
23const WHITE_KING_POSITION_WEIGHTS: [[f64; 8]; 8] = [
24 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
25 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
26 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
27 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
28 [-2.0, -3.0, -3.0, -4.0, -4.0, -3.0, -3.0, -2.0],
29 [-1.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -1.0],
30 [2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0],
31 [2.0, 3.0, 1.0, 0.0, 0.0, 1.0, 3.0, 2.0],
32];
33
34const BLACK_KING_POSITION_WEIGHTS: [[f64; 8]; 8] = [
35 [2.0, 3.0, 1.0, 0.0, 0.0, 1.0, 3.0, 2.0],
36 [2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0],
37 [-1.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -1.0],
38 [-2.0, -3.0, -3.0, -4.0, -4.0, -3.0, -3.0, -2.0],
39 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
40 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
41 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
42 [-3.0, -4.0, -4.0, -5.0, -5.0, -4.0, -4.0, -3.0],
43];
44
45const WHITE_QUEEN_POSITION_WEIGHTS: [[f64; 8]; 8] = [
46 [-2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0],
47 [-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0],
48 [-1.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0],
49 [-0.5, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5],
50 [0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5],
51 [-1.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0],
52 [-1.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, -1.0],
53 [-1.0, -0.0, -1.0, -0.5, -0.5, -0.5, -1.0, -2.0],
54];
55const BLACK_QUEEN_POSITION_WEIGHTS: [[f64; 8]; 8] = [
56 [-1.0, -0.0, -1.0, -0.5, -0.5, -0.5, -1.0, -2.0],
57 [-1.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, -1.0],
58 [-1.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0],
59 [0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5],
60 [-0.5, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -0.5],
61 [-1.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, -1.0],
62 [-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0],
63 [-2.0, -1.0, -1.0, -0.5, -0.5, -1.0, -1.0, -2.0],
64];
65
66const WHITE_ROOK_POSITION_WEIGHTS: [[f64; 8]; 8] = [
67 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
68 [0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5],
69 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
70 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
71 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
72 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
73 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
74 [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0],
75];
76
77const BLACK_ROOK_POSITION_WEIGHTS: [[f64; 8]; 8] = [
78 [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0],
79 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
80 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
81 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
82 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
83 [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5],
84 [0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5],
85 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
86];
87
88const WHITE_BISHOP_POSITION_WEIGHTS: [[f64; 8]; 8] = [
89 [-2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0],
90 [-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0],
91 [-1.0, 0.0, 0.5, 1.0, 1.0, 0.5, 0.0, -1.0],
92 [-1.0, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, -1.0],
93 [-1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0],
94 [-1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0],
95 [-1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, -1.0],
96 [-2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0],
97];
98
99const BLACK_BISHOP_POSITION_WEIGHTS: [[f64; 8]; 8] = [
100 [-2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0],
101 [-1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, -1.0],
102 [-1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0],
103 [-1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0],
104 [-1.0, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, -1.0],
105 [-1.0, 0.0, 0.5, 1.0, 1.0, 0.5, 0.0, -1.0],
106 [-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0],
107 [-2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -2.0],
108];
109
110const WHITE_KNIGHT_POSITION_WEIGHTS: [[f64; 8]; 8] = [
111 [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0],
112 [-4.0, -2.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0],
113 [-3.0, 0.0, 1.0, 1.5, 1.5, 1.0, 0.0, -3.0],
114 [-3.0, 0.5, 1.5, 2.0, 2.0, 1.5, 0.5, -3.0],
115 [-3.0, 0.0, 1.5, 2.0, 2.0, 1.5, 0.0, -3.0],
116 [-3.0, 0.5, 1.0, 1.5, 1.5, 1.0, 0.5, -3.0],
117 [-4.0, -2.0, 0.0, 0.5, 0.5, 0.0, -2.0, -4.0],
118 [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0],
119];
120
121const BLACK_KNIGHT_POSITION_WEIGHTS: [[f64; 8]; 8] = [
122 [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0],
123 [-4.0, -2.0, 0.0, 0.5, 0.5, 0.0, -2.0, -4.0],
124 [-3.0, 0.5, 1.0, 1.5, 1.5, 1.0, 0.5, -3.0],
125 [-3.0, 0.0, 1.5, 2.0, 2.0, 1.5, 0.0, -3.0],
126 [-3.0, 0.5, 1.5, 2.0, 2.0, 1.5, 0.5, -3.0],
127 [-3.0, 0.0, 1.0, 1.5, 1.5, 1.0, 0.0, -3.0],
128 [-4.0, -2.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0],
129 [-5.0, -4.0, -3.0, -3.0, -3.0, -3.0, -4.0, -5.0],
130];
131
132const WHITE_PAWN_POSITION_WEIGHTS: [[f64; 8]; 8] = [
133 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
134 [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0],
135 [1.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 1.0],
136 [0.5, 0.5, 1.0, 2.5, 2.5, 1.0, 0.5, 0.5],
137 [0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0],
138 [0.5, -0.5, -1.0, 0.0, 0.0, -1.0, -0.5, 0.5],
139 [0.5, 1.5, -1.0, -2.0, -2.0, 1.0, 1.5, 0.5],
140 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
141];
142
143const BLACK_PAWN_POSITION_WEIGHTS: [[f64; 8]; 8] = [
144 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
145 [0.5, 1.5, -1.0, -2.0, -2.0, 1.0, 1.5, 0.5],
146 [0.5, -0.5, -1.0, 0.0, 0.0, -1.0, -0.5, 0.5],
147 [0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0],
148 [0.5, 0.5, 1.0, 2.5, 2.5, 1.0, 0.5, 0.5],
149 [1.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 1.0],
150 [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0],
151 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
152];
153
154impl core::fmt::Display for Piece {
155 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
156 write!(
157 f,
158 "{}",
159 match self.get_color() {
160 Color::Black => match self {
161 Self::King(_, _) => "♔",
162 Self::Queen(_, _) => "♕",
163 Self::Rook(_, _) => "♖",
164 Self::Knight(_, _) => "♘",
165 Self::Bishop(_, _) => "♗",
166 Self::Pawn(_, _) => "♙",
167 },
168 Color::White => match self {
169 Self::King(_, _) => "♚",
170 Self::Queen(_, _) => "♛",
171 Self::Rook(_, _) => "♜",
172 Self::Knight(_, _) => "♞",
173 Self::Bishop(_, _) => "♝",
174 Self::Pawn(_, _) => "♟︎",
175 },
176 }
177 )
178 }
179}
180
181impl Piece {
182 #[inline]
185 pub fn get_name(&self) -> &'static str {
186 match self {
187 Self::King(_, _) => "king",
188 Self::Queen(_, _) => "queen",
189 Self::Rook(_, _) => "rook",
190 Self::Bishop(_, _) => "bishop",
191 Self::Knight(_, _) => "knight",
192 Self::Pawn(_, _) => "pawn",
193 }
194 }
195
196 #[inline]
206 pub fn get_material_value(&self) -> i32 {
207 match self {
208 Self::King(_, _) => 99999,
209 Self::Queen(_, _) => 9,
210 Self::Rook(_, _) => 5,
211 Self::Bishop(_, _) => 3,
212 Self::Knight(_, _) => 3,
213 Self::Pawn(_, _) => 1,
214 }
215 }
216
217 #[inline]
226 pub fn get_weighted_value(&self) -> f64 {
227 let weights = match self {
228 Self::King(c, _) => match c {
229 Color::White => WHITE_KING_POSITION_WEIGHTS,
230 Color::Black => BLACK_KING_POSITION_WEIGHTS,
231 },
232 Self::Queen(c, _) => match c {
233 Color::White => WHITE_QUEEN_POSITION_WEIGHTS,
234 Color::Black => BLACK_QUEEN_POSITION_WEIGHTS,
235 },
236 Self::Rook(c, _) => match c {
237 Color::White => WHITE_ROOK_POSITION_WEIGHTS,
238 Color::Black => BLACK_ROOK_POSITION_WEIGHTS,
239 },
240 Self::Bishop(c, _) => match c {
241 Color::White => WHITE_BISHOP_POSITION_WEIGHTS,
242 Color::Black => BLACK_BISHOP_POSITION_WEIGHTS,
243 },
244 Self::Knight(c, _) => match c {
245 Color::White => WHITE_KNIGHT_POSITION_WEIGHTS,
246 Color::Black => BLACK_KNIGHT_POSITION_WEIGHTS,
247 },
248 Self::Pawn(c, _) => match c {
249 Color::White => WHITE_PAWN_POSITION_WEIGHTS,
250 Color::Black => BLACK_PAWN_POSITION_WEIGHTS,
251 },
252 };
253 weights[(7 - self.get_pos().get_row()) as usize][self.get_pos().get_col() as usize]
254 + (self.get_material_value() * 10) as f64
255 }
256
257 #[inline]
259 pub fn with_color(&self, color: Color) -> Self {
260 match *self {
261 Self::King(_, pos) => Self::King(color, pos),
262 Self::Queen(_, pos) => Self::Queen(color, pos),
263 Self::Rook(_, pos) => Self::Rook(color, pos),
264 Self::Bishop(_, pos) => Self::Bishop(color, pos),
265 Self::Knight(_, pos) => Self::Knight(color, pos),
266 Self::Pawn(_, pos) => Self::Pawn(color, pos),
267 }
268 }
269
270 #[inline]
272 pub fn get_color(&self) -> Color {
273 match self {
274 Self::King(c, _)
275 | Self::Queen(c, _)
276 | Self::Rook(c, _)
277 | Self::Bishop(c, _)
278 | Self::Knight(c, _)
279 | Self::Pawn(c, _) => *c,
280 }
281 }
282
283 #[inline]
285 pub fn get_pos(&self) -> Position {
286 match self {
287 Self::King(_, p)
288 | Self::Queen(_, p)
289 | Self::Rook(_, p)
290 | Self::Bishop(_, p)
291 | Self::Knight(_, p)
292 | Self::Pawn(_, p) => *p,
293 }
294 }
295
296 #[inline]
298 pub fn is_king(&self) -> bool {
299 matches!(self, Self::King(_, _))
300 }
301
302 #[inline]
304 pub fn is_queen(&self) -> bool {
305 matches!(self, Self::Queen(_, _))
306 }
307
308 #[inline]
310 pub fn is_rook(&self) -> bool {
311 matches!(self, Self::Rook(_, _))
312 }
313
314 #[inline]
316 pub fn is_bishop(&self) -> bool {
317 matches!(self, Self::Bishop(_, _))
318 }
319
320 #[inline]
322 pub fn is_knight(&self) -> bool {
323 matches!(self, Self::Knight(_, _))
324 }
325
326 #[inline]
328 pub fn is_pawn(&self) -> bool {
329 matches!(self, Self::Pawn(_, _))
330 }
331
332 #[inline]
337 pub fn is_starting_pawn(&self) -> bool {
338 if let Self::Pawn(c, pos) = self {
339 pos.is_starting_pawn(*c)
340 } else {
341 false
342 }
343 }
344
345 #[inline]
350 pub fn is_queenside_rook(&self) -> bool {
351 if let Self::Rook(_, pos) = self {
352 pos.is_queenside_rook()
353 } else {
354 false
355 }
356 }
357
358 #[inline]
363 pub fn is_kingside_rook(&self) -> bool {
364 if let Self::Rook(_, pos) = self {
365 pos.is_kingside_rook()
366 } else {
367 false
368 }
369 }
370
371 #[inline]
378 pub fn move_to(&self, new_pos: Position) -> Self {
379 match *self {
380 Self::King(c, _) => Self::King(c, new_pos),
381 Self::Queen(c, _) => Self::Queen(c, new_pos),
382 Self::Rook(c, _) => Self::Rook(c, new_pos),
383 Self::Bishop(c, _) => Self::Bishop(c, new_pos),
384 Self::Knight(c, _) => Self::Knight(c, new_pos),
385 Self::Pawn(c, _) => Self::Pawn(c, new_pos),
386 }
387 }
388
389 #[inline]
393 pub(crate) fn get_legal_moves(&self, board: &Board) -> Vec<Move> {
394 let mut result = Vec::new();
395 match *self {
396 Self::Pawn(ally_color, pos) => {
397 let up = pos.pawn_up(ally_color);
398 let next_up = up.pawn_up(ally_color);
399 let up_left = up.next_left();
400 let up_right = up.next_right();
401
402 if let Some(en_passant) = board.get_en_passant() {
403 if en_passant == up_left || en_passant == up_right {
404 result.push(Move::Piece(pos, en_passant));
405 }
406 }
407
408 if next_up.is_on_board()
409 && self.is_starting_pawn()
410 && board.has_no_piece(up)
411 && board.has_no_piece(next_up)
412 {
413 result.push(Move::Piece(pos, next_up))
414 }
415
416 if up.is_on_board() && board.has_no_piece(up) {
417 result.push(Move::Piece(pos, up))
418 }
419
420 if up_left.is_on_board() && board.has_enemy_piece(up_left, ally_color) {
421 result.push(Move::Piece(pos, up.next_left()))
422 } else if up_right.is_on_board()
423 && board.has_enemy_piece(up.next_right(), ally_color)
424 {
425 result.push(Move::Piece(pos, up.next_right()))
426 }
427 }
428
429 Self::King(ally_color, pos) => {
430 for p in &[
431 pos.next_left(),
432 pos.next_right(),
433 pos.next_above(),
434 pos.next_below(),
435 pos.next_left().next_above(),
436 pos.next_left().next_below(),
437 pos.next_right().next_above(),
438 pos.next_right().next_below(),
439 ] {
440 if p.is_on_board() && !board.has_ally_piece(*p, ally_color) {
441 result.push(Move::Piece(pos, *p))
442 }
443 }
444 if board.can_kingside_castle(ally_color) {
445 result.push(Move::KingSideCastle);
446 } else if board.can_queenside_castle(ally_color) {
447 result.push(Move::QueenSideCastle);
448 }
449 }
450 Self::Queen(ally_color, pos) => {
451 for row in 0..8 {
452 let new_pos = Position::new(row, pos.get_col());
453 if new_pos != pos
454 && !board.has_ally_piece(new_pos, ally_color)
455 && new_pos.is_orthogonal_to(pos)
456 {
457 result.push(Move::Piece(pos, new_pos));
458 }
459 }
460 for col in 0..8 {
461 let new_pos = Position::new(pos.get_row(), col);
462 if new_pos != pos
463 && !board.has_ally_piece(new_pos, ally_color)
464 && new_pos.is_orthogonal_to(pos)
465 {
466 result.push(Move::Piece(pos, new_pos));
467 }
468 }
469
470 for row in 0..8 {
471 for col in 0..8 {
472 let new_pos = Position::new(row, col);
473 if new_pos != pos
474 && !board.has_ally_piece(new_pos, ally_color)
475 && new_pos.is_diagonal_to(pos)
476 {
477 result.push(Move::Piece(pos, new_pos));
478 }
479 }
480 }
481 }
482
483 Self::Rook(ally_color, pos) => {
484 for row in 0..8 {
485 let new_pos = Position::new(row, pos.get_col());
486 if new_pos != pos
487 && !board.has_ally_piece(new_pos, ally_color)
488 && new_pos.is_orthogonal_to(pos)
489 {
490 result.push(Move::Piece(pos, new_pos));
491 }
492 }
493 for col in 0..8 {
494 let new_pos = Position::new(pos.get_row(), col);
495 if new_pos != pos
496 && !board.has_ally_piece(new_pos, ally_color)
497 && new_pos.is_orthogonal_to(pos)
498 {
499 result.push(Move::Piece(pos, new_pos));
500 }
501 }
502 }
503
504 Self::Bishop(ally_color, pos) => {
505 for row in 0..8 {
506 for col in 0..8 {
507 let new_pos = Position::new(row, col);
508 if new_pos != pos
509 && !board.has_ally_piece(new_pos, ally_color)
510 && new_pos.is_diagonal_to(pos)
511 {
512 result.push(Move::Piece(pos, new_pos));
513 }
514 }
515 }
516 }
517 Self::Knight(ally_color, pos) => {
518 for p in &[
519 pos.next_left().next_left().next_above(),
520 pos.next_left().next_above().next_above(),
521 pos.next_left().next_left().next_below(),
522 pos.next_left().next_below().next_below(),
523 pos.next_right().next_right().next_above(),
524 pos.next_right().next_above().next_above(),
525 pos.next_right().next_right().next_below(),
526 pos.next_right().next_below().next_below(),
527 ] {
528 if p.is_on_board() && !board.has_ally_piece(*p, ally_color) {
529 result.push(Move::Piece(pos, *p))
530 }
531 }
532 }
533 }
534
535 let color = self.get_color();
536 result
537 .into_iter()
538 .filter(|x| match x {
539 Move::Piece(from, to) => {
540 if from.is_on_board() && to.is_on_board() {
541 board.is_legal_move(*x, color)
542 } else {
543 false
544 }
545 }
546 _ => board.is_legal_move(*x, color),
547 })
548 .collect::<Vec<Move>>()
549 }
550
551 #[inline]
553 pub(crate) fn is_legal_move(&self, new_pos: Position, board: &Board) -> bool {
554 if board.has_ally_piece(new_pos, self.get_color()) || new_pos.is_off_board() {
555 return false;
556 }
557
558 match *self {
559 Self::Pawn(ally_color, pos) => {
560 let up = pos.pawn_up(ally_color);
561 let up_left = up.next_left();
562 let up_right = up.next_right();
563
564 (if let Some(en_passant) = board.get_en_passant() {
565 (en_passant == up_left || en_passant == up_right) && (new_pos == en_passant)
566 } else {
567 false
568 }) || (self.is_starting_pawn()
569 && board.has_no_piece(new_pos)
570 && board.has_no_piece(up)
571 && new_pos == up.pawn_up(ally_color))
572 || (board.has_enemy_piece(new_pos, ally_color) && new_pos == up_left)
573 || (board.has_enemy_piece(new_pos, ally_color) && new_pos == up_right)
574 || (board.has_no_piece(new_pos) && new_pos == up)
575 }
576
577 Self::King(_, pos) => pos.is_adjacent_to(new_pos),
578
579 Self::Queen(_, pos) => {
580 if pos.is_orthogonal_to(new_pos) {
581 let mut traveling = pos.orthogonals_to(new_pos);
582 traveling.pop();
583
584 for pos in traveling {
585 if board.has_piece(pos) {
586 return false;
587 }
588 }
589 true
590 } else if pos.is_diagonal_to(new_pos) {
591 let mut traveling = pos.diagonals_to(new_pos);
592 traveling.pop();
593
594 for pos in traveling {
595 if board.has_piece(pos) {
596 return false;
597 }
598 }
599 true
600 } else {
601 false
602 }
603 }
604
605 Self::Rook(_, pos) => {
606 if pos.is_orthogonal_to(new_pos) {
607 let mut traveling = pos.orthogonals_to(new_pos);
608 traveling.pop();
609
610 for pos in traveling {
611 if board.has_piece(pos) {
612 return false;
613 }
614 }
615 true
616 } else {
617 false
618 }
619 }
620
621 Self::Bishop(_, pos) => {
622 if pos.is_diagonal_to(new_pos) {
623 let mut traveling = pos.diagonals_to(new_pos);
624 traveling.pop();
625
626 for pos in traveling {
627 if board.has_piece(pos) {
628 return false;
629 }
630 }
631 true
632 } else {
633 false
634 }
635 }
636
637 Self::Knight(_, pos) => pos.is_knight_move(new_pos),
638 }
639 }
640
641 #[inline]
643 pub(crate) fn is_legal_attack(&self, new_pos: Position, board: &Board) -> bool {
644 if board.has_ally_piece(new_pos, self.get_color()) || new_pos.is_off_board() {
645 return false;
646 }
647
648 match *self {
649 Self::Pawn(ally_color, pos) => {
650 let up = pos.pawn_up(ally_color);
651 (if let Some(en_passant) = board.get_en_passant() {
652 (en_passant == up.next_left() || en_passant == up.next_right())
653 && (new_pos == en_passant)
654 } else {
655 false
656 }) || new_pos == up.next_left()
657 || new_pos == up.next_right()
658 }
659
660 Self::King(_, pos) => pos.is_adjacent_to(new_pos),
661
662 Self::Queen(_, pos) => {
663 if pos.is_orthogonal_to(new_pos) {
664 let mut traveling = pos.orthogonals_to(new_pos);
665 traveling.pop();
666
667 for pos in traveling {
668 if board.has_piece(pos) {
669 return false;
670 }
671 }
672 true
673 } else if pos.is_diagonal_to(new_pos) {
674 let mut traveling = pos.diagonals_to(new_pos);
675 traveling.pop();
676
677 for pos in traveling {
678 if board.has_piece(pos) {
679 return false;
680 }
681 }
682 true
683 } else {
684 false
685 }
686 }
687
688 Self::Rook(_, pos) => {
689 if pos.is_orthogonal_to(new_pos) {
690 let mut traveling = pos.orthogonals_to(new_pos);
691 traveling.pop();
692
693 for pos in traveling {
694 if board.has_piece(pos) {
695 return false;
696 }
697 }
698 true
699 } else {
700 false
701 }
702 }
703
704 Self::Bishop(_, pos) => {
705 if pos.is_diagonal_to(new_pos) {
706 let mut traveling = pos.diagonals_to(new_pos);
707 traveling.pop();
708
709 for pos in traveling {
710 if board.has_piece(pos) {
711 return false;
712 }
713 }
714 true
715 } else {
716 false
717 }
718 }
719
720 Self::Knight(_, pos) => pos.is_knight_move(new_pos),
721 }
722 }
723}