From 2105004dc2aa21908552c950a9c50ad22f37395f Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:08:22 -0800 Subject: [PATCH 01/11] Reimplement Square as an enum; implement Rank and File enums Replace the Square struct with an enum. This implementation is based on this one: https://github.com/analog-hors/magic-bitboards-demo/blob/main/types/src/square.rs This reduces a lot of code needed to construct squares, ranks, and files. --- board/src/lib.rs | 2 +- board/src/square.rs | 372 +++++++++++++++++++++++++------------------- 2 files changed, 209 insertions(+), 165 deletions(-) diff --git a/board/src/lib.rs b/board/src/lib.rs index 61b699d..44d142c 100644 --- a/board/src/lib.rs +++ b/board/src/lib.rs @@ -11,4 +11,4 @@ mod tests; pub use moves::Move; pub use position::Position; -pub use square::Square; +pub use square::{File, Rank, Square}; diff --git a/board/src/square.rs b/board/src/square.rs index bba04e3..8dfb5b7 100644 --- a/board/src/square.rs +++ b/board/src/square.rs @@ -14,110 +14,198 @@ pub enum Direction { NorthEast, } +#[derive(Debug)] +pub struct ParseFileError; + #[derive(Debug)] pub struct ParseSquareError; #[derive(Debug)] pub struct SquareOutOfBoundsError; -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Square { - rank: u8, - file: u8, - index: u8, +macro_rules! coordinate_enum { + ($name: ident, $($variant:ident),*) => { + #[repr(u8)] + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + pub enum $name { + $($variant), * + } + + impl $name { + pub const NUM: usize = [$(Self::$variant), *].len(); + pub const ALL: [Self; Self::NUM] = [$(Self::$variant), *]; + + #[inline] + pub(crate) fn from_index(index: usize) -> Self { + assert!( + index < Self::NUM, + "Index {} out of bounds for {}.", + index, + stringify!($name) + ); + Self::try_index(index).unwrap() + } + + pub fn try_index(index: usize) -> Option { + $( + #[allow(non_upper_case_globals)] + const $variant: usize = $name::$variant as usize; + )* + + match index { + $($variant => Some($name::$variant),)* + _ => None, + } + } + } + } +} + +#[rustfmt::skip] +coordinate_enum!(Rank, + One, Two, Three, Four, Five, Six, Seven, Eight +); + +#[rustfmt::skip] +coordinate_enum!(File, + A, B, C, D, E, F, G, H +); + +#[rustfmt::skip] +coordinate_enum!(Square, + A1, B1, C1, D1, E1, F1, G1, H1, + A2, B2, C2, D2, E2, F2, G2, H2, + A3, B3, C3, D3, E3, F3, G3, H3, + A4, B4, C4, D4, E4, F4, G4, H4, + A5, B5, C5, D5, E5, F5, G5, H5, + A6, B6, C6, D6, E6, F6, G6, H6, + A7, B7, C7, D7, E7, F7, G7, H7, + A8, B8, C8, D8, E8, F8, G8, H8 +); + +impl Into for File { + fn into(self) -> char { + ('a' as u8 + self as u8) as char + } +} + +impl TryFrom for File { + type Error = ParseFileError; + + fn try_from(value: char) -> Result { + let lowercase_value = value.to_ascii_lowercase(); + for file in File::ALL.iter() { + if lowercase_value == (*file).into() { + return Ok(*file); + } + } + + Err(ParseFileError) + } +} + +impl fmt::Display for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Into::::into(*self).to_uppercase()) + } +} + +impl Into for Rank { + fn into(self) -> char { + ('1' as u8 + self as u8) as char + } +} + +impl TryFrom for Rank { + type Error = ParseFileError; + + fn try_from(value: char) -> Result { + let lowercase_value = value.to_ascii_lowercase(); + for rank in Self::ALL.iter().cloned() { + if lowercase_value == rank.into() { + return Ok(rank); + } + } + + Err(ParseFileError) + } +} + +impl fmt::Display for Rank { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Into::::into(*self)) + } } impl Square { - pub fn from_rank_file(rank: u8, file: u8) -> Result { - if rank >= 8 || file >= 8 { - return Err(SquareOutOfBoundsError); - } - - Ok(Square { - rank, - file, - index: rank * 8 + file, - }) + #[inline] + pub fn from_file_rank(file: File, rank: Rank) -> Square { + Self::from_index((rank as usize) << 3 | file as usize) } + #[inline] + pub fn file(self) -> File { + File::from_index(self as usize & 0b000111) + } + + #[inline] + pub fn rank(self) -> Rank { + Rank::from_index(self as usize >> 3) + } +} + +impl Square { pub fn from_algebraic_str(s: &str) -> Result { s.parse() } - pub fn rank_file(&self) -> (u8, u8) { - (self.rank, self.file) - } - - pub fn neighbor(&self, direction: Direction) -> Option { + pub fn neighbor(self, direction: Direction) -> Option { match direction { - Direction::North => Square::from_index(self.index + 8), + Direction::North => Square::try_index(self as usize + 8), Direction::NorthWest => { - if self.rank < 7 { - Square::from_index(self.index + 7) + if self.rank() != Rank::Eight { + Square::try_index(self as usize + 7) } else { - Err(SquareOutOfBoundsError) + None } } Direction::West => { - if self.file > 0 { - Square::from_index(self.index - 1) + if self.file() != File::A { + Square::try_index(self as usize - 1) } else { - Err(SquareOutOfBoundsError) + None } } Direction::SouthWest => { - if self.rank > 0 { - Square::from_index(self.index - 9) + if self.rank() != Rank::One { + Square::try_index(self as usize - 9) } else { - Err(SquareOutOfBoundsError) + None } } Direction::South => { - if self.rank > 0 { - Square::from_index(self.index - 8) + if self.rank() != Rank::One { + Square::try_index(self as usize - 8) } else { - Err(SquareOutOfBoundsError) + None } } Direction::SouthEast => { - if self.rank > 0 { - Square::from_index(self.index - 7) + if self.rank() != Rank::One { + Square::try_index(self as usize - 7) } else { - Err(SquareOutOfBoundsError) + None } } Direction::East => { - if self.file < 7 { - Square::from_index(self.index + 1) + if self.file() != File::H { + Square::try_index(self as usize + 1) } else { - Err(SquareOutOfBoundsError) + None } } - Direction::NorthEast => Square::from_index(self.index + 9), + Direction::NorthEast => Square::try_index(self as usize + 9), } - .ok() - } -} - -impl Square { - pub(crate) fn from_index(index: u8) -> Result { - if index >= 64 { - return Err(SquareOutOfBoundsError); - } - - Ok(Square::from_index_unsafe(index)) - } - - pub(crate) fn from_index_unsafe(index: u8) -> Square { - Square { - rank: index / 8, - file: index % 8, - index: index, - } - } - - pub(crate) fn index(&self) -> u8 { - self.index } } @@ -125,47 +213,34 @@ impl FromStr for Square { type Err = ParseSquareError; fn from_str(s: &str) -> Result { - if !s.is_ascii() || s.len() != 2 { - return Err(ParseSquareError); - } - let mut chars = s.chars(); - let file_char = chars.next().unwrap().to_ascii_lowercase(); - if !file_char.is_ascii_lowercase() { - return Err(ParseSquareError); - } - - let file = (file_char as u8) - ('a' as u8); - if file >= 8 { - return Err(ParseSquareError); - } - - let converted_rank_digit = chars + let file: File = chars .next() - .unwrap() - .to_digit(10) - .and_then(|x| if x >= 1 && x <= 8 { Some(x) } else { None }) + .and_then(|c| c.try_into().ok()) .ok_or(ParseSquareError)?; - let rank = u8::try_from(converted_rank_digit).map_err(|_| ParseSquareError)? - 1; - Ok(Square { - rank, - file, - index: rank * 8 + file, - }) - } -} + let rank: Rank = chars + .next() + .and_then(|c| c.try_into().ok()) + .ok_or(ParseSquareError)?; -impl Into for Square { - fn into(self) -> BitBoard { - BitBoard::new(1 << self.index) + if !chars.next().is_none() { + return Err(ParseSquareError); + } + + Ok(Square::from_file_rank(file, rank)) } } impl fmt::Display for Square { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", ('a' as u8 + self.file) as char, self.rank + 1) + write!( + f, + "{}{}", + ('a' as u8 + self.file() as u8) as char, + self.rank() as usize + 1 + ) } } @@ -175,17 +250,17 @@ mod tests { #[test] fn good_algebraic_input() { - let sq1 = Square::from_algebraic_str("a4").expect("Failed to parse 'a4' square"); - assert_eq!(sq1.file, 0); - assert_eq!(sq1.rank, 3); + let sq = Square::from_algebraic_str("a4").expect("Failed to parse 'a4' square"); + assert_eq!(sq.file(), File::A); + assert_eq!(sq.rank(), Rank::Four); - let sq2 = Square::from_algebraic_str("B8").expect("Failed to parse 'B8' square"); - assert_eq!(sq2.file, 1); - assert_eq!(sq2.rank, 7); + let sq = Square::from_algebraic_str("B8").expect("Failed to parse 'B8' square"); + assert_eq!(sq.file(), File::B); + assert_eq!(sq.rank(), Rank::Eight); - let sq3 = Square::from_algebraic_str("e4").expect("Failed to parse 'B8' square"); - assert_eq!(sq3.rank, 3, "Expected rank of e4 to be 3"); - assert_eq!(sq3.file, 4, "Expected file of e4 to be 4"); + let sq = Square::from_algebraic_str("e4").expect("Failed to parse 'B8' square"); + assert_eq!(sq.file(), File::E); + assert_eq!(sq.rank(), Rank::Four); } #[test] @@ -200,81 +275,50 @@ mod tests { #[test] fn from_index() { - let sq1 = Square::from_index(4).expect("Unable to get Square from index"); - assert_eq!(sq1.rank, 0); - assert_eq!(sq1.file, 4); + let sq = Square::try_index(4).expect("Unable to get Square from index"); + assert_eq!(sq.file(), File::E); + assert_eq!(sq.rank(), Rank::One); - let sq1 = Square::from_index(28).expect("Unable to get Square from index"); - assert_eq!(sq1.rank, 3); - assert_eq!(sq1.file, 4); + let sq = Square::try_index(28).expect("Unable to get Square from index"); + assert_eq!(sq.file(), File::E); + assert_eq!(sq.rank(), Rank::Four); } #[test] fn valid_neighbors() { - let sq = Square::from_index_unsafe(28); + let sq = Square::E4; - assert_eq!( - sq.neighbor(Direction::North), - Some(Square::from_index_unsafe(36)) - ); - - assert_eq!( - sq.neighbor(Direction::NorthEast), - Some(Square::from_index_unsafe(37)) - ); - - assert_eq!( - sq.neighbor(Direction::East), - Some(Square::from_index_unsafe(29)) - ); - - assert_eq!( - sq.neighbor(Direction::SouthEast), - Some(Square::from_index_unsafe(21)) - ); - - assert_eq!( - sq.neighbor(Direction::South), - Some(Square::from_index_unsafe(20)) - ); - - assert_eq!( - sq.neighbor(Direction::SouthWest), - Some(Square::from_index_unsafe(19)) - ); - - assert_eq!( - sq.neighbor(Direction::West), - Some(Square::from_index_unsafe(27)) - ); - - assert_eq!( - sq.neighbor(Direction::NorthWest), - Some(Square::from_index_unsafe(35)) - ); + assert_eq!(sq.neighbor(Direction::North), Some(Square::E5)); + assert_eq!(sq.neighbor(Direction::NorthEast), Some(Square::F5)); + assert_eq!(sq.neighbor(Direction::East), Some(Square::F4)); + assert_eq!(sq.neighbor(Direction::SouthEast), Some(Square::F3)); + assert_eq!(sq.neighbor(Direction::South), Some(Square::E3)); + assert_eq!(sq.neighbor(Direction::SouthWest), Some(Square::D3)); + assert_eq!(sq.neighbor(Direction::West), Some(Square::D4)); + assert_eq!(sq.neighbor(Direction::NorthWest), Some(Square::D5)); } #[test] fn invalid_neighbors() { - let square0 = Square::from_index_unsafe(0); - assert!(square0.neighbor(Direction::West).is_none()); - assert!(square0.neighbor(Direction::SouthWest).is_none()); - assert!(square0.neighbor(Direction::South).is_none()); + let sq = Square::A1; + assert!(sq.neighbor(Direction::West).is_none()); + assert!(sq.neighbor(Direction::SouthWest).is_none()); + assert!(sq.neighbor(Direction::South).is_none()); - let square7 = Square::from_index_unsafe(7); - assert!(square7.neighbor(Direction::East).is_none()); - assert!(square7.neighbor(Direction::SouthEast).is_none()); - assert!(square7.neighbor(Direction::South).is_none()); + let sq = Square::H1; + assert!(sq.neighbor(Direction::East).is_none()); + assert!(sq.neighbor(Direction::SouthEast).is_none()); + assert!(sq.neighbor(Direction::South).is_none()); - let square56 = Square::from_index_unsafe(56); - assert!(square56.neighbor(Direction::North).is_none()); - assert!(square56.neighbor(Direction::NorthWest).is_none()); - assert!(square56.neighbor(Direction::West).is_none()); + let sq = Square::A8; + assert!(sq.neighbor(Direction::North).is_none()); + assert!(sq.neighbor(Direction::NorthWest).is_none()); + assert!(sq.neighbor(Direction::West).is_none()); - let square63 = Square::from_index_unsafe(63); - assert!(square63.neighbor(Direction::North).is_none()); - assert!(square63.neighbor(Direction::NorthEast).is_none()); - assert!(square63.neighbor(Direction::East).is_none()); + let sq = Square::H8; + assert!(sq.neighbor(Direction::North).is_none()); + assert!(sq.neighbor(Direction::NorthEast).is_none()); + assert!(sq.neighbor(Direction::East).is_none()); } #[test] From ff839db041261b2454c228bd7639de08fbb8f307 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:11:52 -0800 Subject: [PATCH 02/11] BitBoard changes - Clean up operator traits: remove the & versions and make the macro do more with less input - Implement From for BitBoards: simplify conversion of Squares to BitBoards - Take BitBoards by value in several places - Clean up unit tests --- board/src/bitboard/bitboard.rs | 95 +++++++++++++++++----------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/board/src/bitboard/bitboard.rs b/board/src/bitboard/bitboard.rs index 7bcd3b8..c268ff7 100644 --- a/board/src/bitboard/bitboard.rs +++ b/board/src/bitboard/bitboard.rs @@ -42,24 +42,22 @@ impl BitBoard { moves_getter!(queen_moves); moves_getter!(king_moves); - pub fn from_square(sq: Square) -> BitBoard { - BitBoard(1 << sq.index()) - } - pub fn is_empty(&self) -> bool { self.0 == 0 } - pub fn has_piece_at(&self, sq: &Square) -> bool { - (self.0 & (1 << sq.index())) > 0 + pub fn has_piece_at(self, sq: Square) -> bool { + !(self & sq.into()).is_empty() } - pub fn place_piece_at(&mut self, sq: &Square) { - self.0 |= 1 << sq.index() + pub fn place_piece_at(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); + *self |= sq_bb } - fn remove_piece_at(&mut self, sq: &Square) { - self.0 &= !(1 << sq.index()) + fn remove_piece_at(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); + *self &= !sq_bb } } @@ -68,7 +66,13 @@ impl BitBoard { BitScanner::new(self.0) .map(|x| u8::try_from(x)) .take_while(|x| x.is_ok()) - .map(|x| Square::from_index_unsafe(x.unwrap())) + .map(|x| Square::from_index(x.unwrap() as usize)) + } +} + +impl From for BitBoard { + fn from(value: Square) -> Self { + BitBoard(1 << value as u64) } } @@ -125,41 +129,35 @@ impl fmt::Debug for BitBoard { } macro_rules! infix_op { - ($trait_type:ident, $func_name:ident, $left_type:ty, $right_type:ty, $op:tt) => { + ($trait_type:ident, $func_name:ident, $left_type:ty, $right_type:ty) => { impl $trait_type<$right_type> for $left_type { type Output = BitBoard; #[inline] fn $func_name(self, rhs: $right_type) -> Self::Output { - BitBoard(self.0 $op rhs.0) + BitBoard($trait_type::$func_name(self.0, rhs.0)) } } }; } macro_rules! assign_op { - ($trait_type:ident, $func_name:ident, $left_type:ty, $op:tt) => { + ($trait_type:ident, $func_name:ident, $left_type:ty) => { impl $trait_type for $left_type { #[inline] fn $func_name(&mut self, rhs: Self) { - self.0 $op rhs.0 + $trait_type::$func_name(&mut self.0, rhs.0) } } }; } -infix_op!(BitAnd, bitand, BitBoard, BitBoard, &); -infix_op!(BitAnd, bitand, &BitBoard, BitBoard, &); -infix_op!(BitAnd, bitand, BitBoard, &BitBoard, &); -infix_op!(BitAnd, bitand, &BitBoard, &BitBoard, &); +infix_op!(BitAnd, bitand, BitBoard, BitBoard); -assign_op!(BitAndAssign, bitand_assign, BitBoard, &=); -assign_op!(BitOrAssign, bitor_assign, BitBoard, |=); +assign_op!(BitAndAssign, bitand_assign, BitBoard); +assign_op!(BitOrAssign, bitor_assign, BitBoard); -infix_op!(BitOr, bitor, BitBoard, BitBoard, |); -infix_op!(BitOr, bitor, &BitBoard, BitBoard, |); -infix_op!(BitOr, bitor, BitBoard, &BitBoard, |); -infix_op!(BitOr, bitor, &BitBoard, &BitBoard, |); +infix_op!(BitOr, bitor, BitBoard, BitBoard); impl Not for BitBoard { type Output = BitBoard; @@ -212,41 +210,44 @@ mod tests { #[test] fn has_piece_at() { let bb = BitBoard(0b1001100); - - let c1 = Square::from_algebraic_str("c1").expect("Unable to get square for 'c1'"); - assert!(bb.has_piece_at(&c1)); - - let b1 = Square::from_algebraic_str("b1").expect("Unable to get square for 'b1'"); - assert!(!bb.has_piece_at(&b1)); + assert!(bb.has_piece_at(Square::C1)); + assert!(!bb.has_piece_at(Square::B1)); } #[test] fn place_piece_at() { - let sq = Square::from_index(34).expect("Invalid square index"); - + let sq = Square::E4; let mut bb = BitBoard(0b1001100); - bb.place_piece_at(&sq); - assert!(bb.has_piece_at(&sq)); + bb.place_piece_at(sq); + assert!(bb.has_piece_at(sq)); } #[test] fn remove_piece_at() { - let sq = Square::from_index(2).expect("Invalid square index"); - + let sq = Square::A3; let mut bb = BitBoard(0b1001100); - bb.remove_piece_at(&sq); - assert!(!bb.has_piece_at(&sq)); + bb.remove_piece_at(sq); + assert!(!bb.has_piece_at(sq)); } #[test] - fn pieces() { - let bb = BitBoard(0x1001_1010); // e4 + fn single_rank_occupancy() { + let bb = BitBoard(0b01010100); + let expected_squares = [Square::G1, Square::E1, Square::C1]; + for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) { + assert_eq!(a, b); + } + } - let mut occupied_squares = bb.occupied_squares(); - assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(28))); - assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(16))); - assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(12))); - assert_eq!(occupied_squares.next(), Some(Square::from_index_unsafe(4))); - assert_eq!(occupied_squares.next(), None); + #[test] + fn occupancy_spot_check() { + let bb = + BitBoard(0b10000000_00000000_00100000_00000100_00000000_00000000_00010000_00001000); + + let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1]; + + for (a, b) in bb.occupied_squares().zip(expected_squares.iter().cloned()) { + assert_eq!(a, b); + } } } From 5a7e498d5d62a5fa8bca1cd5add8e3a5b4bc346d Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:22:22 -0800 Subject: [PATCH 03/11] Iterate on Squares when building the BitBoard library --- board/src/bitboard/library.rs | 42 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/board/src/bitboard/library.rs b/board/src/bitboard/library.rs index 5e78c5a..95a4bf2 100644 --- a/board/src/bitboard/library.rs +++ b/board/src/bitboard/library.rs @@ -83,7 +83,7 @@ impl DiagonalRays { macro_rules! library_getter { ($name:ident) => { pub(super) fn $name(&self, sq: Square) -> BitBoard { - self.$name[sq.index() as usize] + self.$name[sq as usize] } }; } @@ -91,8 +91,8 @@ macro_rules! library_getter { #[derive(Debug)] pub(super) struct MoveLibrary { // Rays - diagonal_rays: [DiagonalRays; 64], - orthogonal_rays: [OrthogonalRays; 64], + diagonal_rays: [DiagonalRays; Square::NUM as usize], + orthogonal_rays: [OrthogonalRays; Square::NUM as usize], // Piecewise move tables knight_moves: [BitBoard; 64], @@ -116,33 +116,31 @@ impl MoveLibrary { } fn init(&mut self) { - for i in 0..64 { - self.init_orthogonal_rays(i); - self.init_diagonal_rays(i); - self.init_knight_moves(i as usize); - self.init_bishop_moves(i as usize); - self.init_rook_moves(i as usize); - self.init_queen_moves(i as usize); - self.init_king_moves(i as usize); + for sq in Square::ALL { + self.init_orthogonal_rays(sq); + self.init_diagonal_rays(sq); + self.init_knight_moves(sq as usize); + self.init_bishop_moves(sq as usize); + self.init_rook_moves(sq as usize); + self.init_queen_moves(sq as usize); + self.init_king_moves(sq as usize); } } - fn init_orthogonal_rays(&mut self, idx: u8) { - let sq = Square::from_index_unsafe(idx); - let sq_bb = BitBoard::from_square(sq); + fn init_orthogonal_rays(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); - let ortho_rays = &mut self.orthogonal_rays[idx as usize]; + let ortho_rays = &mut self.orthogonal_rays[sq as usize]; ortho_rays.positive_file = Self::generate_ray(sq_bb, BitBoard::shift_north_one); ortho_rays.negative_file = Self::generate_ray(sq_bb, BitBoard::shift_south_one); ortho_rays.positive_rank = Self::generate_ray(sq_bb, BitBoard::shift_east_one); ortho_rays.negative_rank = Self::generate_ray(sq_bb, BitBoard::shift_west_one); } - fn init_diagonal_rays(&mut self, idx: u8) { - let sq = Square::from_index_unsafe(idx); - let sq_bb = BitBoard::from_square(sq); + fn init_diagonal_rays(&mut self, sq: Square) { + let sq_bb: BitBoard = sq.into(); - let diag_rays = &mut self.diagonal_rays[idx as usize]; + let diag_rays = &mut self.diagonal_rays[sq as usize]; diag_rays.positive_diagonal = Self::generate_ray(sq_bb, BitBoard::shift_north_east_one); diag_rays.positive_antidiagonal = Self::generate_ray(sq_bb, BitBoard::shift_north_west_one); diag_rays.negative_diagonal = Self::generate_ray(sq_bb, BitBoard::shift_south_west_one); @@ -204,13 +202,13 @@ impl MoveLibrary { } #[inline] - fn generate_ray(sq: BitBoard, shift: fn(&BitBoard) -> BitBoard) -> BitBoard { + fn generate_ray(sq: BitBoard, shift: fn(BitBoard) -> BitBoard) -> BitBoard { let mut ray = BitBoard::empty(); - let mut iter = shift(&sq); + let mut iter = shift(sq); while !iter.is_empty() { ray |= iter; - iter = shift(&iter); + iter = shift(iter); } ray From 657a501cb5106ca2df80817c260d8b2fb1880a62 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:22:39 -0800 Subject: [PATCH 04/11] Take self by value in all BitBoard shift methods --- board/src/bitboard/shifts.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/board/src/bitboard/shifts.rs b/board/src/bitboard/shifts.rs index 2370306..8866d4c 100644 --- a/board/src/bitboard/shifts.rs +++ b/board/src/bitboard/shifts.rs @@ -7,58 +7,58 @@ impl BitBoard { const NOT_H_FILE: u64 = 0x7f7f7f7f7f7f7f7f; #[inline] - pub fn shift_north(&self, n: u8) -> BitBoard { + pub fn shift_north(self, n: u8) -> BitBoard { BitBoard(self.0 << (8 * n)) } #[inline] - pub fn shift_north_one(&self) -> BitBoard { + pub fn shift_north_one(self) -> BitBoard { BitBoard(self.0 << 8) } #[inline] - pub fn shift_north_east_one(&self) -> BitBoard { + pub fn shift_north_east_one(self) -> BitBoard { BitBoard(self.0 << 9 & BitBoard::NOT_A_FILE) } #[inline] - pub fn shift_east(&self, n: u8) -> BitBoard { + pub fn shift_east(self, n: u8) -> BitBoard { // TODO: Implement a bounds check here. BitBoard(self.0 << n) } #[inline] - pub fn shift_east_one(&self) -> BitBoard { + pub fn shift_east_one(self) -> BitBoard { BitBoard(self.0 << 1 & BitBoard::NOT_A_FILE) } #[inline] - pub fn shift_south_east_one(&self) -> BitBoard { + pub fn shift_south_east_one(self) -> BitBoard { BitBoard(self.0 >> 7 & BitBoard::NOT_A_FILE) } #[inline] - pub fn shift_south(&self, n: u8) -> BitBoard { + pub fn shift_south(self, n: u8) -> BitBoard { BitBoard(self.0 >> (8 * n)) } #[inline] - pub fn shift_south_one(&self) -> BitBoard { + pub fn shift_south_one(self) -> BitBoard { BitBoard(self.0 >> 8) } #[inline] - pub fn shift_south_west_one(&self) -> BitBoard { + pub fn shift_south_west_one(self) -> BitBoard { BitBoard(self.0 >> 9 & BitBoard::NOT_H_FILE) } #[inline] - pub fn shift_west_one(&self) -> BitBoard { + pub fn shift_west_one(self) -> BitBoard { BitBoard(self.0 >> 1 & BitBoard::NOT_H_FILE) } #[inline] - pub fn shift_north_west_one(&self) -> BitBoard { + pub fn shift_north_west_one(self) -> BitBoard { BitBoard(self.0 << 7 & BitBoard::NOT_H_FILE) } } From aac1a85507c0ff63b6e8e7ee6e74e8bf8aaaa7cb Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:24:46 -0800 Subject: [PATCH 05/11] In Position::place_piece, take piece and square by value Use values for BitBoards and other things too. --- board/src/position/position.rs | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/board/src/position/position.rs b/board/src/position/position.rs index c9334bd..e22925e 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -1,10 +1,12 @@ // Eryn Wells use super::Pieces; -use crate::bitboard::BitBoard; -use crate::moves::Moves; -use crate::piece::{Color, Piece, PiecePlacementError, PlacedPiece, Shape}; -use crate::Square; +use crate::{ + bitboard::BitBoard, + moves::Moves, + piece::{Color, Piece, PiecePlacementError, PlacedPiece, Shape}, + Square, +}; use std::fmt; use std::fmt::Write; @@ -68,28 +70,24 @@ impl Position { Position { color_to_move: Color::White, pieces_per_color: [ - white_pieces.iter().fold(BitBoard::empty(), |a, b| a | b), - black_pieces.iter().fold(BitBoard::empty(), |a, b| a | b), + white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b), + black_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b), ], pieces_per_type: [white_pieces, black_pieces], } } - pub fn place_piece( - &mut self, - piece: &Piece, - square: &Square, - ) -> Result<(), PiecePlacementError> { + pub fn place_piece(&mut self, piece: Piece, square: Square) -> Result<(), PiecePlacementError> { let type_bb = self.bitboard_for_piece_mut(piece); - if type_bb.has_piece_at(&square) { + if type_bb.has_piece_at(square) { return Err(PiecePlacementError::ExistsOnSquare); } - type_bb.place_piece_at(&square); + type_bb.place_piece_at(square); let color_bb = &mut self.bitboard_for_color_mut(piece.color()); - color_bb.place_piece_at(&square); + color_bb.place_piece_at(square); Ok(()) } @@ -110,16 +108,16 @@ impl Position { | self.pieces_per_color[Color::Black as usize]) } - pub(crate) fn bitboard_for_piece(&self, piece: Piece) -> &BitBoard { - &self.pieces_per_type[piece.color() as usize][piece.shape() as usize] + pub(crate) fn bitboard_for_piece(&self, piece: Piece) -> BitBoard { + self.pieces_per_type[piece.color() as usize][piece.shape() as usize] } - fn bitboard_for_piece_mut(&mut self, piece: &Piece) -> &mut BitBoard { + fn bitboard_for_piece_mut(&mut self, piece: Piece) -> &mut BitBoard { &mut self.pieces_per_type[piece.color() as usize][piece.shape() as usize] } - pub(crate) fn bitboard_for_color(&self, color: Color) -> &BitBoard { - &self.pieces_per_color[color as usize] + pub(crate) fn bitboard_for_color(&self, color: Color) -> BitBoard { + self.pieces_per_color[color as usize] } fn bitboard_for_color_mut(&mut self, color: Color) -> &mut BitBoard { @@ -131,7 +129,7 @@ impl Position { for shape in Shape::iter() { let piece = Piece::new(color, *shape); let bb = self.bitboard_for_piece(piece); - if bb.has_piece_at(&sq) { + if bb.has_piece_at(sq) { return Some(PlacedPiece::new(piece, sq)); } } @@ -185,7 +183,7 @@ mod tests { let square = Square::e4(); position - .place_piece(&piece, &square) + .place_piece(piece, square) .expect("Unable to place white queen on e4"); assert_eq!( @@ -198,7 +196,7 @@ mod tests { ); position - .place_piece(&piece, &square) + .place_piece(piece, square) .expect_err("Placed white queen on e4 a second time?!"); } } From c3e3ebfa9740e72330e82025fdf59ee2b6ad3414 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:25:03 -0800 Subject: [PATCH 06/11] Iterate by Rank and File when building a diagram --- board/src/position/diagram_formatter.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/board/src/position/diagram_formatter.rs b/board/src/position/diagram_formatter.rs index 9f6e4a0..5187ace 100644 --- a/board/src/position/diagram_formatter.rs +++ b/board/src/position/diagram_formatter.rs @@ -1,8 +1,7 @@ // Eryn Wells -use crate::{Position, Square}; -use std::fmt; -use std::fmt::Write; +use crate::{File, Position, Rank, Square}; +use std::{fmt, fmt::Write}; pub struct DiagramFormatter<'a>(&'a Position); @@ -18,11 +17,11 @@ impl<'a> fmt::Display for DiagramFormatter<'a> { output.push_str(" +-----------------+\n"); - for rank in (0..8).rev() { - write!(output, "{} | ", rank + 1)?; + for rank in Rank::ALL.iter().rev() { + write!(output, "{} | ", rank)?; - for file in 0..8 { - let square = Square::from_rank_file(rank, file).unwrap(); + for file in File::ALL.iter() { + let square = Square::from_file_rank(*file, *rank); match self.0.piece_on_square(square) { Some(placed_piece) => write!(output, "{} ", placed_piece.piece())?, None => output.push_str(". "), @@ -56,8 +55,8 @@ mod tests { fn one_king() { let mut pos = Position::empty(); pos.place_piece( - &Piece::king(Color::Black), - &Square::from_algebraic_str("h3").expect("h3"), + Piece::king(Color::Black), + Square::from_algebraic_str("h3").expect("h3"), ) .expect("Unable to place piece"); From c79c05ddb6fc2c16b1cfa9358d2491eb095e1f22 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:34:05 -0800 Subject: [PATCH 07/11] Fix Pieces unit tests --- board/src/position/pieces.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/board/src/position/pieces.rs b/board/src/position/pieces.rs index a8772e8..e3cb87e 100644 --- a/board/src/position/pieces.rs +++ b/board/src/position/pieces.rs @@ -38,7 +38,7 @@ impl<'a> Iterator for Pieces<'a> { } let mut current_shape: Option = None; - let mut next_nonempty_bitboard: Option<&BitBoard> = None; + let mut next_nonempty_bitboard: Option = None; while let Some(shape) = self.shape_iterator.next() { let piece = Piece::new(self.color, *shape); @@ -80,12 +80,8 @@ mod tests { use crate::Square; use std::collections::HashSet; - fn square_at(sq: &str) -> Square { - Square::from_algebraic_str(sq).expect(sq) - } - - fn place_piece_in_position(pos: &mut Position, sq: &str, piece: Piece) { - pos.place_piece(&piece, &square_at(sq)) + fn place_piece_in_position(pos: &mut Position, piece: Piece, sq: Square) { + pos.place_piece(piece, sq) .expect("Unable to place {piece:?} queen on {sq}"); } @@ -98,11 +94,10 @@ mod tests { #[test] fn one() { - let sq = Square::from_algebraic_str("e4").expect("e4"); + let sq = Square::E4; let mut pos = Position::empty(); - pos.place_piece(&Piece::new(Color::White, Shape::Queen), &sq) - .expect("Unable to place white queen on e4"); + place_piece_in_position(&mut pos, Piece::new(Color::White, Shape::Queen), Square::E4); println!("{:?}", &pos); let mut pieces = pos.pieces(Color::White); @@ -117,18 +112,18 @@ mod tests { fn multiple_pieces() { let mut pos = Position::empty(); - place_piece_in_position(&mut pos, "e4", Piece::new(Color::White, Shape::Queen)); - place_piece_in_position(&mut pos, "e1", Piece::new(Color::White, Shape::King)); - place_piece_in_position(&mut pos, "b2", Piece::new(Color::White, Shape::Pawn)); - place_piece_in_position(&mut pos, "c2", Piece::new(Color::White, Shape::Pawn)); + place_piece_in_position(&mut pos, Piece::new(Color::White, Shape::Queen), Square::E4); + place_piece_in_position(&mut pos, Piece::new(Color::White, Shape::King), Square::E1); + place_piece_in_position(&mut pos, Piece::new(Color::White, Shape::Pawn), Square::B2); + place_piece_in_position(&mut pos, Piece::new(Color::White, Shape::Pawn), Square::C2); println!("{:?}", &pos); let expected_placed_pieces = HashSet::from([ - PlacedPiece::new(Piece::new(Color::White, Shape::Queen), square_at("e4")), - PlacedPiece::new(Piece::new(Color::White, Shape::King), square_at("e1")), - PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), square_at("b2")), - PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), square_at("c2")), + PlacedPiece::new(Piece::new(Color::White, Shape::Queen), Square::E4), + PlacedPiece::new(Piece::new(Color::White, Shape::King), Square::E1), + PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), Square::B2), + PlacedPiece::new(Piece::new(Color::White, Shape::Pawn), Square::C2), ]); let placed_pieces = HashSet::from_iter(pos.pieces(Color::White)); From 46495ce5816fc69e3d7a1e5cc203e9ef87e1430b Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:39:11 -0800 Subject: [PATCH 08/11] Update Pawn move generator --- board/src/moves/pawn.rs | 48 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/board/src/moves/pawn.rs b/board/src/moves/pawn.rs index 13650d8..23b31f1 100644 --- a/board/src/moves/pawn.rs +++ b/board/src/moves/pawn.rs @@ -18,9 +18,9 @@ struct MoveIterator(usize, usize); struct MoveGenerationParameters { starting_rank: BitBoard, promotion_rank: BitBoard, - push_shift: fn(&BitBoard) -> BitBoard, - left_capture_shift: fn(&BitBoard) -> BitBoard, - right_capture_shift: fn(&BitBoard) -> BitBoard, + push_shift: fn(BitBoard) -> BitBoard, + left_capture_shift: fn(BitBoard) -> BitBoard, + right_capture_shift: fn(BitBoard) -> BitBoard, } pub(super) struct PawnMoveGenerator<'pos> { @@ -106,7 +106,7 @@ impl<'pos> PawnMoveGenerator<'pos> { let legal_1square_pushes = (parameters.push_shift)(bb) & empty_squares; let legal_2square_pushes = - (parameters.push_shift)(&(legal_1square_pushes & BitBoard::rank(2))) & empty_squares; + (parameters.push_shift)(legal_1square_pushes & BitBoard::rank(2)) & empty_squares; self.pushes = legal_1square_pushes | legal_2square_pushes; } @@ -145,9 +145,9 @@ impl<'pos> PawnMoveGenerator<'pos> { let black_pieces = self.position.bitboard_for_color(self.color.other()); for from_sq in bb.occupied_squares() { - let pawn = BitBoard::from_square(from_sq); + let pawn: BitBoard = from_sq.into(); - let push = (parameters.push_shift)(&pawn); + let push = (parameters.push_shift)(pawn); if !(push & empty_squares).is_empty() { let to_sq = push.occupied_squares().next().unwrap(); @@ -162,7 +162,7 @@ impl<'pos> PawnMoveGenerator<'pos> { } if !(pawn & parameters.starting_rank).is_empty() { - let push = (parameters.push_shift)(&push); + let push = (parameters.push_shift)(push); if !(push & empty_squares).is_empty() { let to_sq = push.occupied_squares().next().unwrap(); self.quiet_move_list() @@ -172,8 +172,8 @@ impl<'pos> PawnMoveGenerator<'pos> { } for attack in [ - (parameters.left_capture_shift)(&pawn), - (parameters.right_capture_shift)(&pawn), + (parameters.left_capture_shift)(pawn), + (parameters.right_capture_shift)(pawn), ] { if !(attack & black_pieces).is_empty() { let to_sq = attack.occupied_squares().next().unwrap(); @@ -254,7 +254,8 @@ mod tests { #[test] fn one_2square_push() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e2()) + + pos.place_piece(Piece::pawn(Color::White), Square::E2) .expect("Failed to place pawn on e2"); let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -275,7 +276,8 @@ mod tests { #[test] fn one_1square_push() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e3()) + + pos.place_piece(Piece::pawn(Color::White), Square::E3) .expect("Failed to place pawn on e3"); let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -297,9 +299,10 @@ mod tests { #[test] fn one_obstructed_2square_push() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e2()) + + pos.place_piece(Piece::pawn(Color::White), Square::E2) .expect("Failed to place pawn on e2"); - pos.place_piece(&Piece::knight(Color::White), &Square::e4()) + pos.place_piece(Piece::knight(Color::White), Square::E4) .expect("Failed to place knight on e4"); println!("{}", DiagramFormatter::new(&pos)); @@ -323,9 +326,10 @@ mod tests { #[test] fn one_obstructed_1square_push() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e2()) + + pos.place_piece(Piece::pawn(Color::White), Square::E2) .expect("Failed to place pawn on e2"); - pos.place_piece(&Piece::knight(Color::White), &Square::e3()) + pos.place_piece(Piece::knight(Color::White), Square::E3) .expect("Failed to place knight on e4"); println!("{}", DiagramFormatter::new(&pos)); @@ -340,11 +344,11 @@ mod tests { #[test] fn one_attack() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e4()) + pos.place_piece(Piece::pawn(Color::White), Square::E4) .expect("Failed to place pawn on e4"); - pos.place_piece(&Piece::bishop(Color::White), &Square::e5()) + pos.place_piece(Piece::bishop(Color::White), Square::E5) .expect("Failed to place pawn on e4"); - pos.place_piece(&Piece::knight(Color::Black), &Square::d5()) + pos.place_piece(Piece::knight(Color::Black), Square::D5) .expect("Failed to place knight on d5"); println!("{}", DiagramFormatter::new(&pos)); @@ -367,13 +371,13 @@ mod tests { #[test] fn one_double_attack() { let mut pos = Position::empty(); - pos.place_piece(&Piece::pawn(Color::White), &Square::e4()) + pos.place_piece(Piece::pawn(Color::White), Square::E4) .expect("Failed to place pawn on e4"); - pos.place_piece(&Piece::bishop(Color::White), &Square::e5()) + pos.place_piece(Piece::bishop(Color::White), Square::E5) .expect("Failed to place pawn on e4"); - pos.place_piece(&Piece::knight(Color::Black), &Square::d5()) + pos.place_piece(Piece::knight(Color::Black), Square::D5) .expect("Failed to place knight on d5"); - pos.place_piece(&Piece::queen(Color::Black), &Square::f5()) + pos.place_piece(Piece::queen(Color::Black), Square::F5) .expect("Failed to place knight on f5"); println!("{}", DiagramFormatter::new(&pos)); From 216140bdbc9405d6af084bfa1936f702ab1c4ccf Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:39:24 -0800 Subject: [PATCH 09/11] Update knight move generator --- board/src/moves/knight.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/src/moves/knight.rs b/board/src/moves/knight.rs index 5a7e921..683b930 100644 --- a/board/src/moves/knight.rs +++ b/board/src/moves/knight.rs @@ -97,7 +97,7 @@ mod tests { #[test] fn one_knight() { let mut pos = Position::empty(); - pos.place_piece(&Piece::knight(Color::White), &Square::e4()) + pos.place_piece(Piece::knight(Color::White), Square::E4) .expect("Failed to place knight on e4"); let generator = KnightMoveGenerator::new(&pos, Color::White); From 3b266cb94a6c802fd4c86be127bd578744e4b3e3 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:40:21 -0800 Subject: [PATCH 10/11] Update king move generator tests --- board/src/moves/king.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/board/src/moves/king.rs b/board/src/moves/king.rs index b345e2e..d1c7287 100644 --- a/board/src/moves/king.rs +++ b/board/src/moves/king.rs @@ -161,13 +161,13 @@ impl<'pos> Iterator for KingMoveGenerator<'pos> { #[cfg(test)] mod tests { use super::*; - use crate::{Position, Square}; + use crate::{piece::Piece, Position, Square}; use std::collections::HashSet; #[test] fn one_king() { let mut pos = Position::empty(); - pos.place_piece(&Piece::king(Color::White), &Square::e4()) + pos.place_piece(Piece::king(Color::White), Square::E4) .expect("Failed to place king on e4"); let generator = KingMoveGenerator::new(&pos, Color::White); @@ -211,7 +211,7 @@ mod tests { #[test] fn one_king_corner() { let mut pos = Position::empty(); - pos.place_piece(&Piece::king(Color::White), &Square::a1()) + pos.place_piece(Piece::king(Color::White), Square::A1) .expect("Failed to place king on a1"); let generator = KingMoveGenerator::new(&pos, Color::White); From 14db74f2129f2123435b7aaa28dc1086f529a447 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 6 Jan 2024 16:45:13 -0800 Subject: [PATCH 11/11] Remove tests module --- board/src/lib.rs | 3 --- board/src/moves/king.rs | 22 +++++++++---------- board/src/moves/knight.rs | 16 +++++++------- board/src/moves/pawn.rs | 32 +++++++++------------------ board/src/position/position.rs | 2 +- board/src/square.rs | 6 ++--- board/src/tests.rs | 40 ---------------------------------- 7 files changed, 33 insertions(+), 88 deletions(-) delete mode 100644 board/src/tests.rs diff --git a/board/src/lib.rs b/board/src/lib.rs index 44d142c..f849d54 100644 --- a/board/src/lib.rs +++ b/board/src/lib.rs @@ -6,9 +6,6 @@ pub mod piece; pub mod position; mod square; -#[cfg(test)] -mod tests; - pub use moves::Move; pub use position::Position; pub use square::{File, Rank, Square}; diff --git a/board/src/moves/king.rs b/board/src/moves/king.rs index d1c7287..abf345d 100644 --- a/board/src/moves/king.rs +++ b/board/src/moves/king.rs @@ -181,14 +181,14 @@ mod tests { ); let expected_moves = [ - Move::new(Piece::king(Color::White), Square::e4(), Square::d5()), - Move::new(Piece::king(Color::White), Square::e4(), Square::e5()), - Move::new(Piece::king(Color::White), Square::e4(), Square::f5()), - Move::new(Piece::king(Color::White), Square::e4(), Square::f4()), - Move::new(Piece::king(Color::White), Square::e4(), Square::f3()), - Move::new(Piece::king(Color::White), Square::e4(), Square::e3()), - Move::new(Piece::king(Color::White), Square::e4(), Square::d3()), - Move::new(Piece::king(Color::White), Square::e4(), Square::d4()), + Move::new(Piece::king(Color::White), Square::E4, Square::D5), + Move::new(Piece::king(Color::White), Square::E4, Square::E5), + Move::new(Piece::king(Color::White), Square::E4, Square::F5), + Move::new(Piece::king(Color::White), Square::E4, Square::F4), + Move::new(Piece::king(Color::White), Square::E4, Square::F3), + Move::new(Piece::king(Color::White), Square::E4, Square::E3), + Move::new(Piece::king(Color::White), Square::E4, Square::D3), + Move::new(Piece::king(Color::White), Square::E4, Square::D4), ]; let mut generated_moves: HashSet = generator.iter().cloned().collect(); @@ -225,9 +225,9 @@ mod tests { ); let expected_moves = [ - Move::new(Piece::king(Color::White), Square::a1(), Square::a2()), - Move::new(Piece::king(Color::White), Square::a1(), Square::b1()), - Move::new(Piece::king(Color::White), Square::a1(), Square::b2()), + Move::new(Piece::king(Color::White), Square::A1, Square::A2), + Move::new(Piece::king(Color::White), Square::A1, Square::B1), + Move::new(Piece::king(Color::White), Square::A1, Square::B2), ]; let mut generated_moves: HashSet = generator.iter().cloned().collect(); diff --git a/board/src/moves/knight.rs b/board/src/moves/knight.rs index 683b930..01711c8 100644 --- a/board/src/moves/knight.rs +++ b/board/src/moves/knight.rs @@ -113,14 +113,14 @@ mod tests { */ let expected_moves = [ - Move::new(Piece::knight(Color::White), Square::e4(), Square::c3()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::d2()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::f2()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::g3()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::c5()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::d6()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::g5()), - Move::new(Piece::knight(Color::White), Square::e4(), Square::f6()), + Move::new(Piece::knight(Color::White), Square::E4, Square::C3), + Move::new(Piece::knight(Color::White), Square::E4, Square::D2), + Move::new(Piece::knight(Color::White), Square::E4, Square::F2), + Move::new(Piece::knight(Color::White), Square::E4, Square::G3), + Move::new(Piece::knight(Color::White), Square::E4, Square::C5), + Move::new(Piece::knight(Color::White), Square::E4, Square::D6), + Move::new(Piece::knight(Color::White), Square::E4, Square::G5), + Move::new(Piece::knight(Color::White), Square::E4, Square::F6), ]; let mut generated_moves: HashSet = generator.iter().cloned().collect(); diff --git a/board/src/moves/pawn.rs b/board/src/moves/pawn.rs index 23b31f1..118ef8b 100644 --- a/board/src/moves/pawn.rs +++ b/board/src/moves/pawn.rs @@ -262,8 +262,8 @@ mod tests { let expected_moves = HashSet::from_iter( [ - Move::new(Piece::pawn(Color::White), Square::e2(), Square::e3()), - Move::new(Piece::pawn(Color::White), Square::e2(), Square::e4()), + Move::new(Piece::pawn(Color::White), Square::E2, Square::E3), + Move::new(Piece::pawn(Color::White), Square::E2, Square::E4), ] .into_iter(), ); @@ -283,12 +283,7 @@ mod tests { let generator = PawnMoveGenerator::new(&pos, Color::White); let expected_moves = HashSet::from_iter( - [Move::new( - Piece::pawn(Color::White), - Square::e3(), - Square::e4(), - )] - .into_iter(), + [Move::new(Piece::pawn(Color::White), Square::E3, Square::E4)].into_iter(), ); let generated_moves: HashSet = generator.collect(); @@ -310,12 +305,7 @@ mod tests { let generator = PawnMoveGenerator::new(&pos, Color::White); let expected_moves = HashSet::from_iter( - [Move::new( - Piece::pawn(Color::White), - Square::e2(), - Square::e3(), - )] - .into_iter(), + [Move::new(Piece::pawn(Color::White), Square::E2, Square::E3)].into_iter(), ); let generated_moves: HashSet = generator.collect(); @@ -356,10 +346,8 @@ mod tests { let generator = PawnMoveGenerator::new(&pos, Color::White); let expected_moves = HashSet::from_iter( - [ - Move::new(Piece::pawn(Color::White), Square::e4(), Square::d5()) - .capturing(PlacedPiece::new(Piece::knight(Color::Black), Square::d5())), - ] + [Move::new(Piece::pawn(Color::White), Square::E4, Square::D5) + .capturing(PlacedPiece::new(Piece::knight(Color::Black), Square::D5))] .into_iter(), ); @@ -386,10 +374,10 @@ mod tests { let expected_moves = HashSet::from_iter( [ - Move::new(Piece::pawn(Color::White), Square::e4(), Square::d5()) - .capturing(PlacedPiece::new(Piece::knight(Color::Black), Square::d5())), - Move::new(Piece::pawn(Color::White), Square::e4(), Square::f5()) - .capturing(PlacedPiece::new(Piece::queen(Color::Black), Square::f5())), + Move::new(Piece::pawn(Color::White), Square::E4, Square::D5) + .capturing(PlacedPiece::new(Piece::knight(Color::Black), Square::D5)), + Move::new(Piece::pawn(Color::White), Square::E4, Square::F5) + .capturing(PlacedPiece::new(Piece::queen(Color::Black), Square::F5)), ] .into_iter(), ); diff --git a/board/src/position/position.rs b/board/src/position/position.rs index e22925e..f1d2b06 100644 --- a/board/src/position/position.rs +++ b/board/src/position/position.rs @@ -180,7 +180,7 @@ mod tests { let mut position = Position::empty(); let piece = Piece::new(Color::White, Shape::Queen); - let square = Square::e4(); + let square = Square::E4; position .place_piece(piece, square) diff --git a/board/src/square.rs b/board/src/square.rs index 8dfb5b7..d4c93e9 100644 --- a/board/src/square.rs +++ b/board/src/square.rs @@ -323,8 +323,8 @@ mod tests { #[test] fn display() { - assert_eq!(format!("{}", Square::c5()), "c5"); - assert_eq!(format!("{}", Square::a1()), "a1"); - assert_eq!(format!("{}", Square::h8()), "h8"); + assert_eq!(format!("{}", Square::C5), "c5"); + assert_eq!(format!("{}", Square::A1), "a1"); + assert_eq!(format!("{}", Square::H8), "h8"); } } diff --git a/board/src/tests.rs b/board/src/tests.rs deleted file mode 100644 index 1bc0085..0000000 --- a/board/src/tests.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Eryn Wells - -/// Test helper utilities. -use crate::Square; - -/// A constructor function that returns a Square representing the square on the -/// chessboard indicated by the algebraic notation. -macro_rules! sq_constructor { - ($func_name:ident) => { - pub(crate) fn $func_name() -> Square { - Square::from_algebraic_str(stringify!($func_name)).expect(stringify!($func_name)) - } - }; -} - -impl Square { - sq_constructor!(a1); - sq_constructor!(a2); - sq_constructor!(b1); - sq_constructor!(b2); - sq_constructor!(c3); - sq_constructor!(c5); - sq_constructor!(d2); - sq_constructor!(d3); - sq_constructor!(d4); - sq_constructor!(d5); - sq_constructor!(d6); - sq_constructor!(e2); - sq_constructor!(e3); - sq_constructor!(e4); - sq_constructor!(e5); - sq_constructor!(f2); - sq_constructor!(f3); - sq_constructor!(f4); - sq_constructor!(f5); - sq_constructor!(f6); - sq_constructor!(g3); - sq_constructor!(g5); - sq_constructor!(h8); -}