From 829d9af52c7949b8ed491035f1f11877df81ca85 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 21 Jan 2024 14:56:03 -0800 Subject: [PATCH] [board] Fix some bugs in the starting position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out I was doing the starting position really wrong. In an upcoming commit, I will implement FEN output for Positions. While doing that work, I found several issues that were causing the output of the FEN formatter to return garbage. Implement a handful of unit tests to track down the errors. Rename Shape::_ascii_representation() → Shape::to_ascii. Implement to_ascii() on Piece. --- board/src/bitboard/bitboard.rs | 9 +++++- board/src/piece.rs | 48 +++++++++++++++------------- board/src/position/piece_sets.rs | 9 ++++-- board/src/position/position.rs | 55 +++++++++++++++++++++++--------- board/src/square.rs | 8 ++++- 5 files changed, 87 insertions(+), 42 deletions(-) diff --git a/board/src/bitboard/bitboard.rs b/board/src/bitboard/bitboard.rs index 6aa4c20..5c35ca8 100644 --- a/board/src/bitboard/bitboard.rs +++ b/board/src/bitboard/bitboard.rs @@ -53,7 +53,8 @@ impl BitBoard { } pub fn is_set(self, sq: Square) -> bool { - !(self & &sq.into()).is_empty() + let square_bitboard: BitBoard = sq.into(); + !(self & square_bitboard).is_empty() } pub fn set_square(&mut self, sq: Square) { @@ -341,4 +342,10 @@ mod tests { assert_eq!(a, bitboard![B5, C5, G7, H3]); } + + #[test] + fn from_square() { + assert_eq!(BitBoard::from(Square::A1), BitBoard(0b1)); + assert_eq!(BitBoard::from(Square::H8), BitBoard(1 << 63)); + } } diff --git a/board/src/piece.rs b/board/src/piece.rs index fa8333d..45ed4b0 100644 --- a/board/src/piece.rs +++ b/board/src/piece.rs @@ -63,7 +63,7 @@ impl Shape { PROMOTABLE_SHAPES.iter() } - fn _ascii_representation(&self) -> char { + fn to_ascii(&self) -> char { match self { Shape::Pawn => 'P', Shape::Knight => 'N', @@ -83,12 +83,12 @@ impl TryFrom for Shape { fn try_from(value: char) -> Result { match value { - 'p' => Ok(Shape::Pawn), - 'N' => Ok(Shape::Knight), - 'B' => Ok(Shape::Bishop), - 'R' => Ok(Shape::Rook), - 'Q' => Ok(Shape::Queen), - 'K' => Ok(Shape::King), + 'P' | 'p' => Ok(Shape::Pawn), + 'N' | 'n' => Ok(Shape::Knight), + 'B' | 'b' => Ok(Shape::Bishop), + 'R' | 'r' => Ok(Shape::Rook), + 'Q' | 'q' => Ok(Shape::Queen), + 'K' | 'k' => Ok(Shape::King), _ => Err(TryFromError), } } @@ -105,13 +105,13 @@ impl TryFrom<&str> for Shape { impl Into for &Shape { fn into(self) -> char { - self._ascii_representation() + self.to_ascii() } } impl Into for Shape { fn into(self) -> char { - self._ascii_representation() + self.to_ascii() } } @@ -173,6 +173,10 @@ impl Piece { is_shape!(is_rook, Rook); is_shape!(is_queen, Queen); is_shape!(is_king, King); + + pub fn to_ascii(&self) -> char { + self.shape.to_ascii() + } } impl fmt::Display for Piece { @@ -193,18 +197,18 @@ impl UnicodeDisplay for Piece { f, "{}", match (self.color, self.shape) { - (Color::White, Shape::Pawn) => '♟', - (Color::White, Shape::Knight) => '♞', - (Color::White, Shape::Bishop) => '♝', - (Color::White, Shape::Rook) => '♜', - (Color::White, Shape::Queen) => '♛', - (Color::White, Shape::King) => '♚', - (Color::Black, Shape::Pawn) => '♙', - (Color::Black, Shape::Knight) => '♘', - (Color::Black, Shape::Bishop) => '♗', - (Color::Black, Shape::Rook) => '♖', - (Color::Black, Shape::Queen) => '♕', - (Color::Black, Shape::King) => '♔', + (Color::Black, Shape::Pawn) => '♟', + (Color::Black, Shape::Knight) => '♞', + (Color::Black, Shape::Bishop) => '♝', + (Color::Black, Shape::Rook) => '♜', + (Color::Black, Shape::Queen) => '♛', + (Color::Black, Shape::King) => '♚', + (Color::White, Shape::Pawn) => '♙', + (Color::White, Shape::Knight) => '♘', + (Color::White, Shape::Bishop) => '♗', + (Color::White, Shape::Rook) => '♖', + (Color::White, Shape::Queen) => '♕', + (Color::White, Shape::King) => '♔', } ) } @@ -212,7 +216,7 @@ impl UnicodeDisplay for Piece { impl FENDisplay for Piece { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ascii = self.shape()._ascii_representation(); + let ascii = self.shape().to_ascii(); write!( f, "{}", diff --git a/board/src/position/piece_sets.rs b/board/src/position/piece_sets.rs index cc01eda..58921b9 100644 --- a/board/src/position/piece_sets.rs +++ b/board/src/position/piece_sets.rs @@ -36,12 +36,15 @@ struct ByColorAndShape([[BitBoard; 6]; 2]); impl PieceBitBoards { pub(super) fn new(pieces: [[BitBoard; 6]; 2]) -> Self { + use std::ops::BitOr; + let white_pieces = pieces[Color::White as usize] .iter() - .fold(BitBoard::empty(), std::ops::BitOr::bitor); - let black_pieces = pieces[Color::White as usize] + .fold(BitBoard::empty(), BitOr::bitor); + let black_pieces = pieces[Color::Black as usize] .iter() - .fold(BitBoard::empty(), std::ops::BitOr::bitor); + .fold(BitBoard::empty(), BitOr::bitor); + let all_pieces = white_pieces | black_pieces; Self { diff --git a/board/src/position/position.rs b/board/src/position/position.rs index 537208d..48c124f 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -33,22 +33,22 @@ impl Position { /// Return a starting position. pub fn starting() -> Self { - let white_pieces = [ - BitBoard::new(0x00FF000000000000), - BitBoard::new(0x4200000000000000), - BitBoard::new(0x2400000000000000), - BitBoard::new(0x8100000000000000), - BitBoard::new(0x1000000000000000), - BitBoard::new(0x0800000000000000), + let black_pieces = [ + BitBoard::new(0b0000000011111111 << 48), + BitBoard::new(0b0100001000000000 << 48), + BitBoard::new(0b0010010000000000 << 48), + BitBoard::new(0b1000000100000000 << 48), + BitBoard::new(0b0000100000000000 << 48), + BitBoard::new(0b0001000000000000 << 48), ]; - let black_pieces = [ - BitBoard::new(0xFF00), - BitBoard::new(0x0042), - BitBoard::new(0x0024), - BitBoard::new(0x0081), - BitBoard::new(0x0010), - BitBoard::new(0x0008), + let white_pieces = [ + BitBoard::new(0b1111111100000000), + BitBoard::new(0b0000000001000010), + BitBoard::new(0b0000000000100100), + BitBoard::new(0b0000000010000001), + BitBoard::new(0b0000000000001000), + BitBoard::new(0b0000000000010000), ]; Self { @@ -242,7 +242,32 @@ impl fmt::Display for Position { #[cfg(test)] mod tests { - use crate::{position, Castle, Color}; + use crate::{position, Castle, Color, Position, Square}; + + #[test] + fn piece_on_square() { + let pos = test_position![ + Black Bishop on F7, + ]; + + let piece = pos.piece_on_square(Square::F7); + assert_eq!(piece, Some(piece!(Black Bishop on F7))); + } + + #[test] + fn piece_in_starting_position() { + let pos = Position::starting(); + println!("{pos}"); + + assert_eq!( + pos.piece_on_square(Square::H1), + Some(piece!(White Rook on H1)) + ); + assert_eq!( + pos.piece_on_square(Square::A8), + Some(piece!(Black Rook on A8)) + ); + } #[test] fn king_is_in_check() { diff --git a/board/src/square.rs b/board/src/square.rs index 4501178..23565cf 100644 --- a/board/src/square.rs +++ b/board/src/square.rs @@ -1,6 +1,6 @@ // Eryn Wells -use crate::{r#move::Castle, Color}; +use crate::Color; use std::{fmt, str::FromStr}; pub enum Direction { @@ -308,6 +308,12 @@ mod tests { assert_eq!(sq.rank(), Rank::Four); } + #[test] + fn to_index() { + assert_eq!(Square::A1 as usize, 0); + assert_eq!(Square::H8 as usize, 63); + } + #[test] fn valid_neighbors() { let sq = Square::E4;