duck_chess/
types.rs

1use crate::engine::BitBoard;
2use crate::lookup::neighbor::has_neighbor;
3
4use std::{
5	fmt::{self, Write},
6	mem,
7};
8
9use serde::{Deserialize, Serialize};
10use serde_big_array::BigArray;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct Board {
15	#[serde(with = "BigArray")]
16	pub board: [Option<Piece>; 64],
17	// white, black
18	pub can_castle: CanCastle,
19	// if the last move was a pawn with two pushes store that position here
20	pub en_passant: Option<Square>,
21	pub next_move: Option<Side>,
22	// if this is true the duck should be moved
23	// and then the side should change
24	pub moved_piece: bool,
25	pub winner: Option<Side>,
26}
27
28// Board
29macro_rules! setup_board {
30	($board:expr, $($id:tt),*) => (
31		$board.board = [
32			$(
33				setup_board!($id)
34			),*
35		];
36	);
37	(e) => (None);
38	(bR) => (Some(Piece { kind: PieceKind::Rook, side: Side::Black }));
39	(bN) => (Some(Piece { kind: PieceKind::Knight, side: Side::Black }));
40	(bB) => (Some(Piece { kind: PieceKind::Bishop, side: Side::Black }));
41	(bQ) => (Some(Piece { kind: PieceKind::Queen, side: Side::Black }));
42	(bK) => (Some(Piece { kind: PieceKind::King, side: Side::Black }));
43	(bP) => (Some(Piece { kind: PieceKind::Pawn, side: Side::Black }));
44	(wR) => (Some(Piece { kind: PieceKind::Rook, side: Side::White }));
45	(wN) => (Some(Piece { kind: PieceKind::Knight, side: Side::White }));
46	(wB) => (Some(Piece { kind: PieceKind::Bishop, side: Side::White }));
47	(wQ) => (Some(Piece { kind: PieceKind::Queen, side: Side::White }));
48	(wK) => (Some(Piece { kind: PieceKind::King, side: Side::White }));
49	(wP) => (Some(Piece { kind: PieceKind::Pawn, side: Side::White }));
50}
51
52impl Board {
53	pub fn new() -> Self {
54		Self {
55			board: [None; 64],
56			can_castle: CanCastle {
57				white: (true, true),
58				black: (true, true),
59			},
60			en_passant: None,
61			next_move: None,
62			moved_piece: false,
63			winner: None,
64		}
65	}
66
67	pub fn set_start_position(&mut self) {
68		#[rustfmt::skip]
69		setup_board!(self,
70			bR, bN, bB, bQ, bK, bB, bN, bR,
71			bP, bP, bP, bP, bP, bP, bP, bP,
72			e, e, e, e, e, e, e, e,
73			e, e, e, e, e, e, e, e,
74			e, e, e, e, e, e, e, e,
75			e, e, e, e, e, e, e, e,
76			wP, wP, wP, wP, wP, wP, wP, wP,
77			wR, wN, wB, wQ, wK, wB, wN, wR
78		);
79		self.can_castle = CanCastle {
80			white: (true, true),
81			black: (true, true),
82		};
83		self.en_passant = None;
84		self.next_move = Some(Side::White);
85		self.moved_piece = false;
86		self.winner = None;
87	}
88
89	pub fn piece_at(&self, square: Square) -> Option<Piece> {
90		unsafe { *self.board.get_unchecked(square as u8 as usize) }
91	}
92
93	pub fn piece_at_mut(&mut self, square: Square) -> &mut Option<Piece> {
94		unsafe { self.board.get_unchecked_mut(square as u8 as usize) }
95	}
96
97	fn can_eat_piece(piece: Piece, side: Side) -> bool {
98		!piece.kind.is_duck() && piece.side != side
99	}
100
101	/// returns (valid, captures)
102	fn valid_square_for_piece(
103		&self,
104		square: Square,
105		side: Side,
106	) -> (bool, Option<PieceKind>) {
107		let Some(piece) = self.piece_at(square) else {
108			return (true, None);
109		};
110
111		let valid = Self::can_eat_piece(piece, side);
112		if valid {
113			(true, Some(piece.kind))
114		} else {
115			(false, None)
116		}
117	}
118
119	fn available_moves_by_dir(
120		&self,
121		from: Square,
122		dirs: &[Direction],
123		// if only one move can be done (true for king)
124		max_one: bool,
125		list: &mut Vec<PieceMove>,
126	) {
127		let dist = if max_one { 1 } else { 8 };
128		let Some(piece) = self.piece_at(from) else {
129			panic!("no piece")
130		};
131
132		for dir in dirs {
133			let mut to = from;
134			for _ in 0..dist {
135				if !to.apply_dir(*dir) {
136					break;
137				}
138
139				let (valid, capture) =
140					self.valid_square_for_piece(to, piece.side);
141
142				if !valid {
143					break;
144				}
145
146				list.push(PieceMove::Piece {
147					piece: piece.kind,
148					from,
149					to,
150					capture,
151					promotion: None,
152				});
153
154				// cannot capture a piece after a capture
155				if capture.is_some() {
156					break;
157				}
158			}
159		}
160	}
161
162	// the square needs to be the position of the king
163	fn available_castle_moves(
164		&self,
165		square: Square,
166		list: &mut Vec<PieceMove>,
167	) {
168		const LONG_FREE: &[u8] = &[1, 2, 3];
169		const SHORT_FREE: &[u8] = &[5, 6];
170
171		let Some(piece) = self.piece_at(square) else {
172			panic!("no piece")
173		};
174
175		let (y, (can_castle_long, can_castle_short)) = match piece.side {
176			Side::White => (7, self.can_castle.white),
177			Side::Black => (0, self.can_castle.black),
178		};
179
180		if can_castle_long {
181			let all_free = LONG_FREE
182				.iter()
183				.map(|x| Square::from_xy(*x, y))
184				.all(|square| self.piece_at(square).is_none());
185
186			if all_free {
187				list.push(PieceMove::Castle {
188					from_king: square,
189					to_king: Square::from_xy(2, y),
190					from_rook: Square::from_xy(0, y),
191					to_rook: Square::from_xy(3, y),
192				});
193			}
194		}
195
196		if can_castle_short {
197			let all_free = SHORT_FREE
198				.iter()
199				.map(|x| Square::from_xy(*x, y))
200				.all(|square| self.piece_at(square).is_none());
201
202			if all_free {
203				list.push(PieceMove::Castle {
204					from_king: square,
205					to_king: Square::from_xy(6, y),
206					from_rook: Square::from_xy(7, y),
207					to_rook: Square::from_xy(5, y),
208				});
209			}
210		}
211	}
212
213	fn available_pawn_moves(&self, square: Square, list: &mut Vec<PieceMove>) {
214		const CAN_PROMOTE_TO: &[PieceKind] = &[
215			PieceKind::Rook,
216			PieceKind::Knight,
217			PieceKind::Bishop,
218			PieceKind::Queen,
219		];
220		const DIRECTION_WHITE: Direction = Direction::Up;
221		const DIRECTION_BLACK: Direction = Direction::Down;
222		const TAKE_PIECE_WHITE: &[Direction] =
223			&[Direction::UpLeft, Direction::UpRight];
224		const TAKE_PIECE_BLACK: &[Direction] =
225			&[Direction::DownLeft, Direction::DownRight];
226
227		let Some(piece) = self.piece_at(square) else {
228			panic!("no piece")
229		};
230
231		let (second_rank, to_promotion, dir, take_dirs) = match piece.side {
232			Side::White => (6, 1, DIRECTION_WHITE, TAKE_PIECE_WHITE),
233			Side::Black => (1, 6, DIRECTION_BLACK, TAKE_PIECE_BLACK),
234		};
235		let can_promote = square.y() == to_promotion;
236
237		let move_dist = if square.y() == second_rank { 2 } else { 1 };
238
239		// move up
240		{
241			let mut up_square = square;
242			for _ in 0..move_dist {
243				if !up_square.apply_dir(dir)
244					|| self.piece_at(up_square).is_some()
245				{
246					break;
247				}
248
249				list.push(PieceMove::Piece {
250					piece: piece.kind,
251					from: square,
252					to: up_square,
253					capture: None,
254					promotion: None,
255				});
256			}
257		}
258
259		// promotion
260		if can_promote {
261			let promotion_square = square.add_dir(dir).unwrap();
262			if self.piece_at(promotion_square).is_none() {
263				for promotion_piece in CAN_PROMOTE_TO {
264					list.push(PieceMove::Piece {
265						piece: piece.kind,
266						from: square,
267						to: promotion_square,
268						capture: None,
269						promotion: Some(*promotion_piece),
270					});
271				}
272			}
273		}
274
275		// take piece
276		for dir in take_dirs {
277			let Some(new_square) = square.add_dir(*dir) else {
278				continue;
279			};
280
281			let Some(eat_piece) = self.piece_at(new_square) else {
282				continue;
283			};
284
285			if Self::can_eat_piece(eat_piece, piece.side) {
286				list.push(PieceMove::Piece {
287					piece: piece.kind,
288					from: square,
289					to: new_square,
290					capture: Some(eat_piece.kind),
291					promotion: None,
292				});
293			}
294		}
295
296		// en passant
297		if let Some(en_passant_square) = self.en_passant {
298			// needs to be besides the pawn and on the same rank
299			if en_passant_square.y() != square.y()
300				|| square.x().abs_diff(en_passant_square.x()) != 1
301			{
302				return;
303			}
304
305			let mut new_square = en_passant_square;
306			new_square.apply_dir(dir);
307
308			list.push(PieceMove::EnPassant {
309				from: square,
310				to: new_square,
311			});
312		}
313	}
314
315	fn available_knight_moves(
316		&self,
317		square: Square,
318		list: &mut Vec<PieceMove>,
319	) {
320		let Some(piece) = self.piece_at(square) else {
321			panic!("no piece")
322		};
323
324		for dir in Direction::ALL_KNIGHTS {
325			let Some(new_square) = square.add_dir(*dir) else {
326				continue;
327			};
328
329			let capture = if let Some(eat_piece) = self.piece_at(new_square) {
330				if !Self::can_eat_piece(eat_piece, piece.side) {
331					continue;
332				}
333
334				Some(eat_piece.kind)
335			} else {
336				None
337			};
338
339			list.push(PieceMove::Piece {
340				piece: piece.kind,
341				from: square,
342				to: new_square,
343				capture,
344				promotion: None,
345			});
346		}
347	}
348
349	pub fn available_piece_moves(
350		&self,
351		piece: PieceKind,
352		square: Square,
353		list: &mut Vec<PieceMove>,
354	) {
355		assert!(!self.moved_piece);
356		assert!(self.next_move.is_some());
357
358		match piece {
359			PieceKind::Rook | PieceKind::Bishop | PieceKind::Queen => {
360				self.available_moves_by_dir(
361					square,
362					piece.directions(),
363					false,
364					list,
365				);
366			}
367			PieceKind::King => {
368				self.available_moves_by_dir(
369					square,
370					piece.directions(),
371					true,
372					list,
373				);
374
375				self.available_castle_moves(square, list);
376			}
377			PieceKind::Pawn => {
378				self.available_pawn_moves(square, list);
379			}
380			PieceKind::Knight => {
381				self.available_knight_moves(square, list);
382			}
383			PieceKind::Duck => unreachable!(),
384		}
385	}
386
387	pub fn available_duck_squares(&self, list: &mut Vec<Square>) {
388		assert!(self.moved_piece);
389
390		for (square, piece) in iter_board!(self.board) {
391			if piece.is_none() {
392				list.push(square);
393			}
394		}
395	}
396
397	/// only returns square which a piece is surounding
398	pub fn reasonable_duck_squares(&self, list: &mut Vec<Square>) {
399		assert!(self.moved_piece);
400		assert!(list.is_empty());
401
402		let oponnent = self.next_move.unwrap().other();
403		let mut oponnent_pieces = BitBoard::new();
404
405		// gather data
406		for (square, piece) in iter_board!(self.board) {
407			let Some(piece) = piece else { continue };
408
409			if piece.side == oponnent || piece.kind.is_duck() {
410				oponnent_pieces.set(square);
411			}
412		}
413
414		// do the check
415		for (square, piece) in iter_board!(self.board) {
416			if piece.is_some() {
417				continue;
418			}
419
420			if has_neighbor(square, oponnent_pieces) {
421				list.push(square);
422			}
423		}
424	}
425
426	// set can castle for the correct side
427	pub fn set_can_castle(&mut self, can_castle: bool, long: bool) {
428		match self.next_move.unwrap() {
429			Side::White if long => {
430				self.can_castle.white.0 = can_castle;
431			}
432			Side::White => {
433				self.can_castle.white.1 = can_castle;
434			}
435			Side::Black if long => {
436				self.can_castle.black.0 = can_castle;
437			}
438			Side::Black => {
439				self.can_castle.black.1 = can_castle;
440			}
441		}
442	}
443
444	// the move needs to be valid
445	#[cfg_attr(feature = "flamegraph", inline(never))]
446	pub fn apply_piece_move(&mut self, mv: PieceMove) {
447		assert!(!self.moved_piece);
448		let side = self.next_move.unwrap();
449
450		let mut new_en_passant = None;
451
452		match mv {
453			PieceMove::Piece {
454				piece,
455				from,
456				to,
457				promotion,
458				..
459			} => {
460				match piece {
461					PieceKind::Rook => {
462						// long
463						if from.x() == 0 {
464							self.set_can_castle(false, true);
465						// short
466						} else if from.x() == 7 {
467							self.set_can_castle(false, false);
468						}
469					}
470					PieceKind::King => {
471						self.set_can_castle(false, true);
472						self.set_can_castle(false, false);
473					}
474					PieceKind::Pawn => {
475						// check if it is a double move
476						if from.x() == to.x() && from.y().abs_diff(to.y()) == 2
477						{
478							new_en_passant = Some(to);
479						}
480					}
481					_ => {}
482				}
483
484				// now do the move
485				let new_piece = match promotion {
486					Some(kind) => Piece { kind, side },
487					None => self.piece_at(from).unwrap(),
488				};
489
490				*self.piece_at_mut(from) = None;
491
492				match self.piece_at(to).map(|p| p.kind) {
493					Some(PieceKind::King) => {
494						self.winner = Some(side);
495						self.next_move = None;
496					}
497					_ => {}
498				}
499				self.piece_at_mut(to).replace(new_piece);
500			}
501			PieceMove::EnPassant { from, to } => {
502				let square = self.en_passant.take().unwrap();
503				*self.piece_at_mut(square) = None;
504				let pawn = self.piece_at(from).unwrap();
505				*self.piece_at_mut(from) = None;
506				self.piece_at_mut(to).replace(pawn);
507			}
508			PieceMove::Castle {
509				from_king,
510				to_king,
511				from_rook,
512				to_rook,
513			} => {
514				let king = self.piece_at(from_king).unwrap();
515				let rook = self.piece_at(from_rook).unwrap();
516				*self.piece_at_mut(from_king) = None;
517				*self.piece_at_mut(from_rook) = None;
518				self.piece_at_mut(to_king).replace(king);
519				self.piece_at_mut(to_rook).replace(rook);
520
521				self.set_can_castle(false, true);
522				self.set_can_castle(false, false);
523			}
524		}
525
526		// we moved something reset values
527		self.en_passant = new_en_passant;
528		self.moved_piece = true;
529	}
530
531	#[cfg_attr(feature = "flamegraph", inline(never))]
532	pub fn apply_duck_move(
533		&mut self,
534		square: Square,
535		duck_square: Option<Square>,
536	) {
537		assert!(self.moved_piece);
538		let next_move = self.next_move.unwrap();
539
540		// remove the duck if it exists
541		// for piece in self.board.iter_mut() {
542		// 	if matches!(piece, Some(p) if p.kind.is_duck()) {
543		// 		*piece = None;
544		// 	}
545		// }
546		if let Some(duck_square) = duck_square {
547			*self.piece_at_mut(duck_square) = None;
548		}
549
550		self.piece_at_mut(square).replace(Piece {
551			kind: PieceKind::Duck,
552			side: next_move,
553		});
554
555		self.moved_piece = false;
556		self.next_move = Some(next_move.other());
557	}
558}
559
560#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
561#[serde(rename_all = "camelCase")]
562pub struct Piece {
563	pub kind: PieceKind,
564	pub side: Side,
565}
566
567#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
568pub enum PieceKind {
569	Rook,
570	Knight,
571	Bishop,
572	King,
573	Queen,
574	Pawn,
575	Duck,
576}
577
578impl PieceKind {
579	// returns an empty slice if the piece does not work with directions
580	pub fn directions(&self) -> &'static [Direction] {
581		use Direction::*;
582		match self {
583			Self::Rook => &[Up, Right, Down, Left],
584			Self::Knight => &[],
585			Self::Bishop => &[UpRight, DownRight, DownLeft, UpLeft],
586			Self::King => Direction::ALL_NO_KNIGHTS,
587			Self::Queen => Direction::ALL_NO_KNIGHTS,
588			Self::Pawn => &[],
589			Self::Duck => &[],
590		}
591	}
592
593	pub fn is_duck(&self) -> bool {
594		matches!(self, Self::Duck)
595	}
596}
597
598#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
599#[serde(rename_all = "camelCase")]
600pub struct CanCastle {
601	// long, short
602	pub white: (bool, bool),
603	pub black: (bool, bool),
604}
605
606#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
607pub enum Side {
608	White,
609	Black,
610}
611
612impl Side {
613	pub fn other(&self) -> Self {
614		match self {
615			Self::White => Self::Black,
616			Self::Black => Self::White,
617		}
618	}
619
620	// returns +1 for White and -1 for Black
621	pub fn multi(&self) -> f32 {
622		match self {
623			Self::White => 1f32,
624			Self::Black => -1f32,
625		}
626	}
627}
628
629#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
630#[serde(rename_all = "camelCase")]
631pub struct Move {
632	pub piece: PieceMove,
633	// A move is allowed to have no duck, this typically only happens
634	// in a winning move but who knows
635	pub duck: Option<Square>,
636	pub side: Side,
637}
638
639#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
640#[serde(tag = "kind", rename_all_fields = "camelCase")]
641pub enum PieceMove {
642	Piece {
643		piece: PieceKind,
644		from: Square,
645		to: Square,
646		capture: Option<PieceKind>,
647		promotion: Option<PieceKind>,
648	},
649	EnPassant {
650		from: Square,
651		to: Square,
652	},
653	Castle {
654		from_king: Square,
655		to_king: Square,
656		from_rook: Square,
657		to_rook: Square,
658	},
659}
660
661#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
662#[repr(u8)]
663#[rustfmt::skip]
664pub enum Square {
665	A8 = 0, B8, C8, D8, E8, F8, G8, H8,
666	A7, B7, C7, D7, E7, F7, G7, H7,
667	A6, B6, C6, D6, E6, F6, G6, H6,
668	A5, B5, C5, D5, E5, F5, G5, H5,
669	A4, B4, C4, D4, E4, F4, G4, H4,
670	A3, B3, C3, D3, E3, F3, G3, H3,
671	A2, B2, C2, D2, E2, F2, G2, H2,
672	A1, B1, C1, D1, E1, F1, G1, H1,
673}
674
675impl Square {
676	// ## Panics if the number is 64 >=
677	#[inline]
678	pub const fn from_u8(num: u8) -> Self {
679		assert!(num < 64);
680		unsafe { mem::transmute(num) }
681	}
682
683	/// the number needs to be lower than 64
684	pub unsafe fn from_u8_unchecked(num: u8) -> Self {
685		unsafe { mem::transmute(num) }
686	}
687
688	pub fn x(&self) -> u8 {
689		*self as u8 % 8
690	}
691
692	// returns the lower case letter of the x coordinate
693	pub fn x_letter(&self) -> u8 {
694		self.x() + b'a'
695	}
696
697	pub fn y(&self) -> u8 {
698		*self as u8 / 8
699	}
700
701	// needs to be valid coordinates 0-7 0-7
702	#[inline]
703	pub const fn from_xy(x: u8, y: u8) -> Self {
704		Square::from_u8(y * 8 + x)
705	}
706
707	#[inline]
708	pub fn add_dir(&self, dir: Direction) -> Option<Self> {
709		let mut xy = (self.x() as i8, self.y() as i8);
710		dir.update_xy(&mut xy);
711
712		let (x, y) = xy;
713		if x < 0 || x >= 8 || y < 0 || y >= 8 {
714			return None;
715		}
716
717		Some(Self::from_xy(x as u8, y as u8))
718	}
719
720	/// returns true if the move was applied
721	#[inline]
722	pub fn apply_dir(&mut self, dir: Direction) -> bool {
723		if let Some(next) = self.add_dir(dir) {
724			*self = next;
725			true
726		} else {
727			false
728		}
729	}
730}
731
732impl fmt::Display for Square {
733	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734		write!(f, "{}{}", self.x_letter() as char, self.y() + 1)
735	}
736}
737
738#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
739pub enum Direction {
740	Up,
741	UpRight,
742	Right,
743	DownRight,
744	Down,
745	DownLeft,
746	Left,
747	UpLeft,
748	KnUpRight,
749	KnRightUp,
750	KnRightDown,
751	KnDownRight,
752	KnDownLeft,
753	KnLeftDown,
754	KnLeftUp,
755	KnUpLeft,
756}
757
758impl Direction {
759	const ALL_NO_KNIGHTS: &'static [Self] = &[
760		Self::Up,
761		Self::UpRight,
762		Self::Right,
763		Self::DownRight,
764		Self::Down,
765		Self::DownLeft,
766		Self::Left,
767		Self::UpLeft,
768	];
769
770	const ALL_KNIGHTS: &'static [Self] = &[
771		Self::KnUpRight,
772		Self::KnRightUp,
773		Self::KnRightDown,
774		Self::KnDownRight,
775		Self::KnDownLeft,
776		Self::KnLeftDown,
777		Self::KnLeftUp,
778		Self::KnUpLeft,
779	];
780
781	fn xy_change(&self) -> (i8, i8) {
782		match self {
783			Self::Up => (0, -1),
784			Self::UpRight => (1, -1),
785			Self::Right => (1, 0),
786			Self::DownRight => (1, 1),
787			Self::Down => (0, 1),
788			Self::DownLeft => (-1, 1),
789			Self::Left => (-1, 0),
790			Self::UpLeft => (-1, -1),
791			// knight
792			Self::KnUpRight => (1, -2),
793			Self::KnRightUp => (2, -1),
794			Self::KnRightDown => (2, 1),
795			Self::KnDownRight => (1, 2),
796			Self::KnDownLeft => (-1, 2),
797			Self::KnLeftDown => (-2, 1),
798			Self::KnLeftUp => (-2, -1),
799			Self::KnUpLeft => (-1, -2),
800		}
801	}
802
803	fn update_xy(&self, xy: &mut (i8, i8)) {
804		let change = self.xy_change();
805		xy.0 += change.0;
806		xy.1 += change.1;
807	}
808}
809
810#[cfg(test)]
811mod tests {
812	use super::*;
813
814	fn sq_xy(square: Square) -> (u8, u8) {
815		(square.x(), square.y())
816	}
817
818	#[test]
819	fn square_xy() {
820		assert_eq!(sq_xy(Square::A8), (0, 0));
821		assert_eq!(sq_xy(Square::H8), (7, 0));
822		assert_eq!(sq_xy(Square::A1), (0, 7));
823		assert_eq!(sq_xy(Square::H1), (7, 7));
824		assert_eq!(Square::from_xy(0, 0), Square::A8);
825		assert_eq!(Square::from_xy(7, 0), Square::H8);
826		assert_eq!(Square::from_xy(0, 7), Square::A1);
827		assert_eq!(Square::from_xy(7, 7), Square::H1);
828	}
829
830	#[test]
831	fn apply_dir() {
832		let mut square = Square::E4;
833		assert!(square.apply_dir(Direction::Up));
834		assert_eq!(square, Square::E5);
835		assert!(square.apply_dir(Direction::UpLeft));
836		assert_eq!(square, Square::D6);
837	}
838}