1use std::fmt;
2use std::ops;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[repr(u8)]
9pub enum Square {
10 A1,
11 B1,
12 C1,
13 D1,
14 E1,
15 F1,
16 G1,
17 H1,
18 A2,
19 B2,
20 C2,
21 D2,
22 E2,
23 F2,
24 G2,
25 H2,
26 A3,
27 B3,
28 C3,
29 D3,
30 E3,
31 F3,
32 G3,
33 H3,
34 A4,
35 B4,
36 C4,
37 D4,
38 E4,
39 F4,
40 G4,
41 H4,
42 A5,
43 B5,
44 C5,
45 D5,
46 E5,
47 F5,
48 G5,
49 H5,
50 A6,
51 B6,
52 C6,
53 D6,
54 E6,
55 F6,
56 G6,
57 H6,
58 A7,
59 B7,
60 C7,
61 D7,
62 E7,
63 F7,
64 G7,
65 H7,
66 A8,
67 B8,
68 C8,
69 D8,
70 E8,
71 F8,
72 G8,
73 H8,
74 NONE,
75}
76
77pub const SQ_A1: Square = Square::A1;
78pub const SQ_B1: Square = Square::B1;
79pub const SQ_C1: Square = Square::C1;
80pub const SQ_D1: Square = Square::D1;
81pub const SQ_E1: Square = Square::E1;
82pub const SQ_F1: Square = Square::F1;
83pub const SQ_G1: Square = Square::G1;
84pub const SQ_H1: Square = Square::H1;
85pub const SQ_A2: Square = Square::A2;
86pub const SQ_B2: Square = Square::B2;
87pub const SQ_C2: Square = Square::C2;
88pub const SQ_D2: Square = Square::D2;
89pub const SQ_E2: Square = Square::E2;
90pub const SQ_F2: Square = Square::F2;
91pub const SQ_G2: Square = Square::G2;
92pub const SQ_H2: Square = Square::H2;
93pub const SQ_A3: Square = Square::A3;
94pub const SQ_B3: Square = Square::B3;
95pub const SQ_C3: Square = Square::C3;
96pub const SQ_D3: Square = Square::D3;
97pub const SQ_E3: Square = Square::E3;
98pub const SQ_F3: Square = Square::F3;
99pub const SQ_G3: Square = Square::G3;
100pub const SQ_H3: Square = Square::H3;
101pub const SQ_A4: Square = Square::A4;
102pub const SQ_B4: Square = Square::B4;
103pub const SQ_C4: Square = Square::C4;
104pub const SQ_D4: Square = Square::D4;
105pub const SQ_E4: Square = Square::E4;
106pub const SQ_F4: Square = Square::F4;
107pub const SQ_G4: Square = Square::G4;
108pub const SQ_H4: Square = Square::H4;
109pub const SQ_A5: Square = Square::A5;
110pub const SQ_B5: Square = Square::B5;
111pub const SQ_C5: Square = Square::C5;
112pub const SQ_D5: Square = Square::D5;
113pub const SQ_E5: Square = Square::E5;
114pub const SQ_F5: Square = Square::F5;
115pub const SQ_G5: Square = Square::G5;
116pub const SQ_H5: Square = Square::H5;
117pub const SQ_A6: Square = Square::A6;
118pub const SQ_B6: Square = Square::B6;
119pub const SQ_C6: Square = Square::C6;
120pub const SQ_D6: Square = Square::D6;
121pub const SQ_E6: Square = Square::E6;
122pub const SQ_F6: Square = Square::F6;
123pub const SQ_G6: Square = Square::G6;
124pub const SQ_H6: Square = Square::H6;
125pub const SQ_A7: Square = Square::A7;
126pub const SQ_B7: Square = Square::B7;
127pub const SQ_C7: Square = Square::C7;
128pub const SQ_D7: Square = Square::D7;
129pub const SQ_E7: Square = Square::E7;
130pub const SQ_F7: Square = Square::F7;
131pub const SQ_G7: Square = Square::G7;
132pub const SQ_H7: Square = Square::H7;
133pub const SQ_A8: Square = Square::A8;
134pub const SQ_B8: Square = Square::B8;
135pub const SQ_C8: Square = Square::C8;
136pub const SQ_D8: Square = Square::D8;
137pub const SQ_E8: Square = Square::E8;
138pub const SQ_F8: Square = Square::F8;
139pub const SQ_G8: Square = Square::G8;
140pub const SQ_H8: Square = Square::H8;
141pub const SQUARE_NB: usize = 64;
143pub const FILE_NB: usize = 8;
145pub const RANK_NB: usize = 8;
147
148pub(crate) const SQUARES: [Square; 64] = [
150 Square::A1,
151 Square::B1,
152 Square::C1,
153 Square::D1,
154 Square::E1,
155 Square::F1,
156 Square::G1,
157 Square::H1,
158 Square::A2,
159 Square::B2,
160 Square::C2,
161 Square::D2,
162 Square::E2,
163 Square::F2,
164 Square::G2,
165 Square::H2,
166 Square::A3,
167 Square::B3,
168 Square::C3,
169 Square::D3,
170 Square::E3,
171 Square::F3,
172 Square::G3,
173 Square::H3,
174 Square::A4,
175 Square::B4,
176 Square::C4,
177 Square::D4,
178 Square::E4,
179 Square::F4,
180 Square::G4,
181 Square::H4,
182 Square::A5,
183 Square::B5,
184 Square::C5,
185 Square::D5,
186 Square::E5,
187 Square::F5,
188 Square::G5,
189 Square::H5,
190 Square::A6,
191 Square::B6,
192 Square::C6,
193 Square::D6,
194 Square::E6,
195 Square::F6,
196 Square::G6,
197 Square::H6,
198 Square::A7,
199 Square::B7,
200 Square::C7,
201 Square::D7,
202 Square::E7,
203 Square::F7,
204 Square::G7,
205 Square::H7,
206 Square::A8,
207 Square::B8,
208 Square::C8,
209 Square::D8,
210 Square::E8,
211 Square::F8,
212 Square::G8,
213 Square::H8,
214];
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
218#[repr(u8)]
219#[non_exhaustive]
220pub enum File {
221 A,
222 B,
223 C,
224 D,
225 E,
226 F,
227 G,
228 H,
229}
230
231impl File {
232 pub const NB: usize = 8;
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
237#[repr(u8)]
238#[non_exhaustive]
239pub enum Rank {
240 R1,
241 R2,
242 R3,
243 R4,
244 R5,
245 R6,
246 R7,
247 R8,
248}
249
250impl Rank {
251 pub const NB: usize = 8;
252}
253
254pub fn file_of(s: Square) -> File {
256 static FILES: [File; 8] = [
257 File::A,
258 File::B,
259 File::C,
260 File::D,
261 File::E,
262 File::F,
263 File::G,
264 File::H,
265 ];
266 FILES[(s as u8 & 7) as usize]
267}
268
269pub fn rank_of(s: Square) -> Rank {
271 static RANKS: [Rank; 8] = [
272 Rank::R1,
273 Rank::R2,
274 Rank::R3,
275 Rank::R4,
276 Rank::R5,
277 Rank::R6,
278 Rank::R7,
279 Rank::R8,
280 ];
281 RANKS[((s as u8 >> 3) & 7) as usize]
282}
283
284pub fn make_square(f: File, r: Rank) -> Square {
286 let idx = (r as usize) * 8 + (f as usize);
287 SQUARES[idx]
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
296pub struct Bitboard(pub u64);
297
298impl Bitboard {
299 pub const EMPTY: Bitboard = Bitboard(0);
301
302 #[must_use]
304 pub fn is_empty(self) -> bool {
305 self.0 == 0
306 }
307
308 #[must_use]
310 pub fn count(self) -> u32 {
311 self.0.count_ones()
312 }
313
314 #[must_use]
319 pub fn lsb(self) -> Square {
320 debug_assert!(!self.is_empty());
321 let idx = self.0.trailing_zeros() as u8;
322 unsafe { std::mem::transmute(idx) }
325 }
326
327 pub fn pop_lsb(&mut self) -> Square {
329 let sq = self.lsb();
330 self.0 &= self.0 - 1;
331 sq
332 }
333
334 #[must_use]
336 pub fn more_than_one(self) -> bool {
337 self.0 & (self.0 - 1) != 0
338 }
339
340 pub fn square_bb(sq: Square) -> Bitboard {
343 if sq == Square::NONE {
344 return Bitboard::EMPTY;
345 }
346 Bitboard(1u64 << (sq as u8))
347 }
348}
349
350impl ops::BitAnd for Bitboard {
351 type Output = Bitboard;
352 fn bitand(self, rhs: Bitboard) -> Bitboard {
353 Bitboard(self.0 & rhs.0)
354 }
355}
356
357impl ops::BitOr for Bitboard {
358 type Output = Bitboard;
359 fn bitor(self, rhs: Bitboard) -> Bitboard {
360 Bitboard(self.0 | rhs.0)
361 }
362}
363
364impl ops::BitXor for Bitboard {
365 type Output = Bitboard;
366 fn bitxor(self, rhs: Bitboard) -> Bitboard {
367 Bitboard(self.0 ^ rhs.0)
368 }
369}
370
371impl ops::Not for Bitboard {
372 type Output = Bitboard;
373 fn not(self) -> Bitboard {
374 Bitboard(!self.0)
375 }
376}
377
378impl ops::Shl<usize> for Bitboard {
379 type Output = Bitboard;
380 fn shl(self, rhs: usize) -> Bitboard {
381 Bitboard(self.0 << rhs)
382 }
383}
384
385impl ops::Shr<usize> for Bitboard {
386 type Output = Bitboard;
387 fn shr(self, rhs: usize) -> Bitboard {
388 Bitboard(self.0 >> rhs)
389 }
390}
391
392impl ops::BitAnd<Square> for Bitboard {
393 type Output = Bitboard;
394 fn bitand(self, rhs: Square) -> Bitboard {
395 self & Bitboard::square_bb(rhs)
396 }
397}
398
399impl ops::BitOr<Square> for Bitboard {
400 type Output = Bitboard;
401 fn bitor(self, rhs: Square) -> Bitboard {
402 self | Bitboard::square_bb(rhs)
403 }
404}
405
406impl ops::BitXor<Square> for Bitboard {
407 type Output = Bitboard;
408 fn bitxor(self, rhs: Square) -> Bitboard {
409 self ^ Bitboard::square_bb(rhs)
410 }
411}
412
413impl ops::Sub<Square> for Bitboard {
414 type Output = Bitboard;
415 fn sub(self, rhs: Square) -> Bitboard {
416 self & !Bitboard::square_bb(rhs)
417 }
418}
419
420impl ops::BitAnd<Square> for Square {
421 type Output = Bitboard;
422 fn bitand(self, rhs: Square) -> Bitboard {
423 Bitboard::square_bb(self) & rhs
424 }
425}
426
427impl ops::BitOr<Square> for Square {
428 type Output = Bitboard;
429 fn bitor(self, rhs: Square) -> Bitboard {
430 Bitboard::square_bb(self) | rhs
431 }
432}
433
434#[derive(Debug, Clone, Copy, PartialEq, Eq)]
436#[non_exhaustive]
437pub enum Color {
438 White = 0,
439 Black = 1,
440}
441
442impl Color {
443 pub const NB: usize = 2;
444
445 pub fn flip(self) -> Color {
447 match self {
448 Color::White => Color::Black,
449 Color::Black => Color::White,
450 }
451 }
452}
453
454#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
459#[repr(u8)]
460#[non_exhaustive]
461pub enum PieceType {
462 Pawn = 0,
463 Knight = 1,
464 Bishop = 2,
465 Rook = 3,
466 Queen = 4,
467 Commoner = 5,
468}
469
470impl PieceType {
471 pub const NB: usize = 6;
472}
473
474#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479pub struct Piece(u8);
480
481impl Piece {
482 pub const fn from_parts(color: Color, pt: PieceType) -> Piece {
484 Piece(((color as u8) << 3) | ((pt as u8) + 1))
485 }
486
487 #[must_use]
489 pub fn color(self) -> Color {
490 if self.0 & 8 == 0 {
491 Color::White
492 } else {
493 Color::Black
494 }
495 }
496
497 #[must_use]
499 pub fn type_of(self) -> PieceType {
500 let inner = (self.0 & 7) - 1;
501 debug_assert!(
502 inner < 6,
503 "Piece::type_of called with invalid Piece encoding: inner={}",
504 inner
505 );
506 unsafe { std::mem::transmute(inner) }
509 }
510
511 #[must_use]
515 pub fn ascii_char(self) -> char {
516 let t = match self.type_of() {
517 PieceType::Pawn => 'P',
518 PieceType::Knight => 'N',
519 PieceType::Bishop => 'B',
520 PieceType::Rook => 'R',
521 PieceType::Queen => 'Q',
522 PieceType::Commoner => 'C',
523 };
524 match self.color() {
525 Color::White => t,
526 Color::Black => t.to_ascii_lowercase(),
527 }
528 }
529}
530
531impl fmt::Display for Piece {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 if self.0 == 0 {
534 return write!(f, "--");
535 }
536 let c = match self.color() {
537 Color::White => "W",
538 Color::Black => "B",
539 };
540 write!(f, "{}{}", c, self.ascii_char().to_ascii_uppercase())
541 }
542}
543
544pub const NO_PIECE: Piece = Piece(0);
545pub const W_PAWN: Piece = Piece::from_parts(Color::White, PieceType::Pawn);
546pub const W_KNIGHT: Piece = Piece::from_parts(Color::White, PieceType::Knight);
547pub const W_BISHOP: Piece = Piece::from_parts(Color::White, PieceType::Bishop);
548pub const W_ROOK: Piece = Piece::from_parts(Color::White, PieceType::Rook);
549pub const W_QUEEN: Piece = Piece::from_parts(Color::White, PieceType::Queen);
550pub const W_COMMONER: Piece = Piece::from_parts(Color::White, PieceType::Commoner);
551pub const B_PAWN: Piece = Piece::from_parts(Color::Black, PieceType::Pawn);
552pub const B_KNIGHT: Piece = Piece::from_parts(Color::Black, PieceType::Knight);
553pub const B_BISHOP: Piece = Piece::from_parts(Color::Black, PieceType::Bishop);
554pub const B_ROOK: Piece = Piece::from_parts(Color::Black, PieceType::Rook);
555pub const B_QUEEN: Piece = Piece::from_parts(Color::Black, PieceType::Queen);
556pub const B_COMMONER: Piece = Piece::from_parts(Color::Black, PieceType::Commoner);
557
558pub fn make_piece(color: Color, pt: PieceType) -> Piece {
560 Piece::from_parts(color, pt)
561}
562
563#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
565#[non_exhaustive]
566pub enum MoveType {
567 Normal = 0,
568 Promotion = 1,
569 EnPassant = 2,
570 Castling = 3,
571}
572
573#[derive(Debug, Clone, Copy, PartialEq, Eq)]
578pub struct Move(u16);
579
580impl Move {
581 pub const NONE: Move = Move(0);
583 pub const NULL: Move = Move(1 + (1 << 6));
585
586 #[must_use]
588 pub fn from_sq(self) -> Square {
589 let idx = ((self.0 >> 6) & 0x3f) as u8;
590 unsafe { std::mem::transmute(idx) }
593 }
594
595 #[must_use]
597 pub fn to_sq(self) -> Square {
598 let idx = (self.0 & 0x3f) as u8;
599 unsafe { std::mem::transmute(idx) }
602 }
603
604 #[must_use]
606 pub fn move_type(self) -> MoveType {
607 match (self.0 >> 12) & 3 {
608 0 => MoveType::Normal,
609 1 => MoveType::Promotion,
610 2 => MoveType::EnPassant,
611 _ => MoveType::Castling,
612 }
613 }
614
615 #[must_use]
617 pub fn promotion_type(self) -> PieceType {
618 static TYPES: [PieceType; 4] = [
619 PieceType::Knight,
620 PieceType::Bishop,
621 PieceType::Rook,
622 PieceType::Queen,
623 ];
624 TYPES[((self.0 >> 14) & 3) as usize]
625 }
626
627 pub fn make_move(from: Square, to: Square) -> Move {
629 Move(((from as u16) << 6) | (to as u16))
630 }
631
632 pub fn make_promotion(from: Square, to: Square, pt: PieceType) -> Move {
634 let pt_bits = match pt {
635 PieceType::Knight => 0u16,
636 PieceType::Bishop => 1u16,
637 PieceType::Rook => 2u16,
638 PieceType::Queen => 3u16,
639 _ => 0u16,
640 };
641 Move((pt_bits << 14) | (1 << 12) | ((from as u16) << 6) | (to as u16))
642 }
643
644 pub fn make_enpassant(from: Square, to: Square) -> Move {
646 Move((2 << 12) | ((from as u16) << 6) | (to as u16))
647 }
648
649 pub fn make_castling(from: Square, to: Square) -> Move {
651 Move((3 << 12) | ((from as u16) << 6) | (to as u16))
652 }
653}
654
655#[derive(Debug, Clone, Copy, PartialEq, Eq)]
657pub enum Direction {
658 North = 8,
659 East = 1,
660 South = -8,
661 West = -1,
662 NorthEast = 9,
663 NorthWest = 7,
664 SouthEast = -7,
665 SouthWest = -9,
666}
667
668impl ops::Add<Direction> for Square {
669 type Output = Square;
670 fn add(self, rhs: Direction) -> Square {
671 let idx = (self as i16) + (rhs as i16);
672 if (0..64).contains(&idx) {
673 SQUARES[idx as usize]
674 } else {
675 Square::NONE
676 }
677 }
678}
679
680impl ops::Sub<Direction> for Square {
681 type Output = Square;
682 fn sub(self, rhs: Direction) -> Square {
683 let idx = (self as i16) - (rhs as i16);
684 if (0..64).contains(&idx) {
685 SQUARES[idx as usize]
686 } else {
687 Square::NONE
688 }
689 }
690}
691
692pub const MAX_MOVES: usize = 256;
699
700#[derive(Debug, Clone)]
706pub struct MoveList {
707 moves: [Move; MAX_MOVES],
708 len: usize,
709}
710
711impl MoveList {
712 #[inline]
714 pub fn new() -> Self {
715 MoveList {
716 moves: [Move::NONE; MAX_MOVES],
717 len: 0,
718 }
719 }
720
721 #[inline]
723 pub fn len(&self) -> usize {
724 self.len
725 }
726
727 #[inline]
729 pub fn is_empty(&self) -> bool {
730 self.len == 0
731 }
732
733 #[inline]
740 pub fn push(&mut self, m: Move) {
741 debug_assert!(self.len < MAX_MOVES, "MoveList overflow");
742 if self.len < MAX_MOVES {
744 self.moves[self.len] = m;
745 self.len += 1;
746 }
747 }
748
749 #[inline]
752 pub(crate) fn set_len(&mut self, len: usize) {
753 debug_assert!(len <= MAX_MOVES, "MoveList::set_len overflow");
754 self.len = len;
755 }
756
757 #[inline]
759 pub fn as_slice(&self) -> &[Move] {
760 &self.moves[..self.len]
761 }
762
763 #[inline]
765 pub fn as_mut_slice(&mut self) -> &mut [Move] {
766 let len = self.len;
767 &mut self.moves[..len]
768 }
769}
770
771#[doc(hidden)]
777pub fn sq_str(sq: Square) -> String {
778 let files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
779 let idx = sq as usize;
780 format!("{}{}", files[idx % 8], (idx / 8 + 1))
781}
782
783#[doc(hidden)]
789pub fn parse_sq(s: &str) -> Square {
790 if s.len() < 2 {
791 return Square::A1;
792 }
793 let file = match s.chars().next().unwrap() {
794 'a' => 0,
795 'b' => 1,
796 'c' => 2,
797 'd' => 3,
798 'e' => 4,
799 'f' => 5,
800 'g' => 6,
801 'h' => 7,
802 _ => 0,
803 };
804 let rank = match s.chars().nth(1).unwrap() {
805 '1' => Rank::R1,
806 '2' => Rank::R2,
807 '3' => Rank::R3,
808 '4' => Rank::R4,
809 '5' => Rank::R5,
810 '6' => Rank::R6,
811 '7' => Rank::R7,
812 '8' => Rank::R8,
813 _ => Rank::R1,
814 };
815 make_square(
816 match file {
817 0 => File::A,
818 1 => File::B,
819 2 => File::C,
820 3 => File::D,
821 4 => File::E,
822 5 => File::F,
823 6 => File::G,
824 7 => File::H,
825 _ => unreachable!(),
826 },
827 rank,
828 )
829}
830
831impl Default for MoveList {
832 fn default() -> Self {
833 Self::new()
834 }
835}
836
837impl<'a> IntoIterator for &'a MoveList {
839 type Item = Move;
840 type IntoIter = MoveListIter<'a>;
841
842 fn into_iter(self) -> MoveListIter<'a> {
843 MoveListIter {
844 iter: self.as_slice().iter(),
845 }
846 }
847}
848
849pub struct MoveListIter<'a> {
853 iter: std::slice::Iter<'a, Move>,
854}
855
856impl<'a> Iterator for MoveListIter<'a> {
857 type Item = Move;
858
859 #[inline]
860 fn next(&mut self) -> Option<Move> {
861 self.iter.next().copied()
862 }
863
864 #[inline]
865 fn size_hint(&self) -> (usize, Option<usize>) {
866 self.iter.size_hint()
867 }
868}
869
870impl<'a> ExactSizeIterator for MoveListIter<'a> {}
871
872impl ops::Index<usize> for MoveList {
873 type Output = Move;
874
875 #[inline]
876 fn index(&self, index: usize) -> &Move {
877 &self.moves[index]
878 }
879}
880
881impl ops::IndexMut<usize> for MoveList {
882 #[inline]
883 fn index_mut(&mut self, index: usize) -> &mut Move {
884 &mut self.moves[index]
885 }
886}
887
888#[cfg(test)]
889mod tests {
890 use super::*;
891
892 #[test]
893 fn test_square_conversion() {
894 let sq = make_square(File::A, Rank::R1);
895 assert_eq!(sq, Square::A1);
896 assert_eq!(file_of(sq), File::A);
897 assert_eq!(rank_of(sq), Rank::R1);
898
899 let sq = make_square(File::H, Rank::R8);
900 assert_eq!(sq, Square::H8);
901 assert_eq!(file_of(sq), File::H);
902 assert_eq!(rank_of(sq), Rank::R8);
903 }
904
905 #[test]
906 fn test_bitboard_ops() {
907 let b1 = Bitboard(0xFF);
908 let b2 = Bitboard(0x0F);
909 assert_eq!((b1 & b2).0, 0x0F);
910 assert_eq!((b1 | b2).0, 0xFF);
911 assert_eq!((!b1).0, !0xFFu64);
912 assert_eq!(Bitboard::square_bb(Square::A1).0, 1);
913 assert_eq!(Bitboard::square_bb(Square::H8).0, 1u64 << 63);
914 }
915
916 #[test]
917 fn test_move_encoding() {
918 let m = Move::make_move(Square::A2, Square::A4);
919 assert_eq!(m.from_sq(), Square::A2);
920 assert_eq!(m.to_sq(), Square::A4);
921 assert_eq!(m.move_type(), MoveType::Normal);
922
923 let m = Move::make_enpassant(Square::C5, Square::D6);
924 assert_eq!(m.move_type(), MoveType::EnPassant);
925
926 let m = Move::make_castling(Square::E1, Square::H1);
927 assert_eq!(m.move_type(), MoveType::Castling);
928
929 let m = Move::make_promotion(Square::A7, Square::A8, PieceType::Queen);
930 assert_eq!(m.move_type(), MoveType::Promotion);
931 assert_eq!(m.promotion_type(), PieceType::Queen);
932 }
933
934 #[test]
935 fn test_piece() {
936 let wp = make_piece(Color::White, PieceType::Pawn);
937 assert_eq!(wp.color(), Color::White);
938 assert_eq!(wp.type_of(), PieceType::Pawn);
939
940 let bk = make_piece(Color::Black, PieceType::Commoner);
941 assert_eq!(bk.color(), Color::Black);
942 assert_eq!(bk.type_of(), PieceType::Commoner);
943 }
944}