diff --git a/src/fen.rs b/src/fen.rs index 04429dc..bc16e1f 100644 --- a/src/fen.rs +++ b/src/fen.rs @@ -1,4 +1,4 @@ -use crate::{Board, ColPiece, Color, Square, BOARD_HEIGHT, BOARD_WIDTH}; +use crate::{Board, ColPiece, Color, Square, SquareIdx, BOARD_HEIGHT, BOARD_WIDTH}; pub const START_POSITION: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; @@ -179,7 +179,7 @@ impl FromFen for Board { parse_space_and_goto!(FenState::HalfMove); } 'a'..='h' => { - pos.ep_square = Some(Square(c as usize - 'a' as usize)); + pos.ep_square = Some(Square(c as SquareIdx - b'a')); parser_state = FenState::EnPassantFile; } _ => return bad_char!(i, c), @@ -188,8 +188,8 @@ impl FromFen for Board { FenState::EnPassantFile => { if let Some(digit) = c.to_digit(10) { pos.ep_square = Some(Square( - usize::from(pos.ep_square.unwrap_or(Square(0))) - + (digit as usize - 1) * 8, + SquareIdx::from(pos.ep_square.unwrap_or(Square(0))) + + (digit as SquareIdx - 1) * 8, )); } else { return bad_char!(i, c); @@ -287,7 +287,7 @@ mod tests { let fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"; let board = Board::from_fen(fen.into()).unwrap(); assert_eq!( - (0..N_SQUARES) + (0..SquareIdx::try_from(N_SQUARES).unwrap()) .map(Square) .map(|i| board.get_piece(i)) .map(ColPiece::opt_to_char) diff --git a/src/lib.rs b/src/lib.rs index bd0c2e4..02fb87e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,11 +109,13 @@ impl ColPiece { } } +type SquareIdx = u8; + /// Square index newtype. /// /// A1 is (0, 0) -> 0, A2 is (0, 1) -> 2, and H8 is (7, 7) -> 63. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Square(usize); +pub struct Square(SquareIdx); #[derive(Debug)] pub enum SquareError { @@ -121,11 +123,11 @@ pub enum SquareError { InvalidCharacter(char), } -impl TryFrom for Square { +impl TryFrom for Square { type Error = SquareError; - fn try_from(value: usize) -> Result { - if (0..N_SQUARES).contains(&value) { + fn try_from(value: SquareIdx) -> Result { + if (0..N_SQUARES).contains(&value.into()) { Ok(Square(value)) } else { Err(SquareError::OutOfBounds) @@ -141,7 +143,7 @@ macro_rules! sq_try_from { fn try_from(value: $T) -> Result { if let Ok(upper_bound) = <$T>::try_from(N_SQUARES) { if (0..upper_bound).contains(&value) { - return Ok(Square(value as usize)); + return Ok(Square(value as SquareIdx)); } } Err(SquareError::OutOfBounds) @@ -150,13 +152,20 @@ macro_rules! sq_try_from { }; } +sq_try_from!(i8); sq_try_from!(i32); sq_try_from!(isize); -sq_try_from!(i8); +sq_try_from!(usize); + +impl From for SquareIdx { + fn from(value: Square) -> Self { + value.0 + } +} impl From for usize { fn from(value: Square) -> Self { - value.0 + value.0.into() } } @@ -181,10 +190,10 @@ impl Square { } fn to_row_col(self) -> (usize, usize) { //! Get row, column from index - let div = self.0 / BOARD_WIDTH; - let rem = self.0 % BOARD_WIDTH; - assert!(div <= 7); - assert!(rem <= 7); + let div = usize::from(self.0) / BOARD_WIDTH; + let rem = usize::from(self.0) % BOARD_WIDTH; + debug_assert!(div <= 7); + debug_assert!(rem <= 7); (div, rem) } fn to_row_col_signed(self) -> (isize, isize) { @@ -313,7 +322,7 @@ impl Iterator for BitboardIterator { None } else { let next_idx = self.remaining.0.trailing_zeros() as usize; - let sq = Square(next_idx); + let sq = Square(next_idx.try_into().unwrap()); self.remaining.off_sq(sq); Some(sq) } @@ -620,10 +629,10 @@ mod tests { try_type!(i32); try_type!(i8); try_type!(isize); - try_type!(usize); + try_type!(u8); } - let good_cases = 0..N_SQUARES; + let good_cases = 0..SquareIdx::try_from(N_SQUARES).unwrap(); for tc in good_cases { macro_rules! try_type { ($T: ty) => { @@ -635,7 +644,7 @@ mod tests { try_type!(i32); try_type!(i8); try_type!(isize); - try_type!(usize); + try_type!(u8); } } @@ -653,10 +662,7 @@ mod tests { #[test] fn test_bitboard_iteration() { - let indices = [ - 0usize, 5usize, 17usize, 24usize, 34usize, 39usize, 42usize, 45usize, 49usize, 50usize, - 63usize, - ]; + let indices = [0, 5, 17, 24, 34, 39, 42, 45, 49, 50, 63]; let mut bitboard = Bitboard::default(); diff --git a/src/movegen.rs b/src/movegen.rs index a454820..87843d4 100644 --- a/src/movegen.rs +++ b/src/movegen.rs @@ -228,8 +228,8 @@ impl Move { ); // square to actually capture at let ep_capture = Square::try_from(match pc_src.col { - Color::White => self.dest.0 - BOARD_WIDTH, - Color::Black => self.dest.0 + BOARD_WIDTH, + Color::White => usize::from(self.dest.0) - BOARD_WIDTH, + Color::Black => usize::from(self.dest.0) + BOARD_WIDTH, }) .expect("En-passant capture square should be valid"); @@ -302,14 +302,16 @@ impl Move { Color::White => { if self.src == Square(0) { castle.q = false; - } else if self.src == Square(BOARD_WIDTH - 1) { + } else if self.src == Square::try_from(BOARD_WIDTH - 1).unwrap() { castle.k = false; }; } Color::Black => { - if self.src == Square((BOARD_HEIGHT - 1) * BOARD_WIDTH) { + if self.src + == Square::try_from((BOARD_HEIGHT - 1) * BOARD_WIDTH).unwrap() + { castle.q = false; - } else if self.src == Square(N_SQUARES - 1) { + } else if self.src == Square::try_from(N_SQUARES - 1).unwrap() { castle.k = false; }; } @@ -722,7 +724,7 @@ pub fn perft(depth: usize, pos: &mut Board) -> usize { #[cfg(test)] mod tests { use super::*; - use crate::fen::{ToFen, START_POSITION, FromFen}; + use crate::fen::{FromFen, ToFen, START_POSITION}; #[test] /// Ensure that bitboard properly reflects captures.