refactor: make square idx size type a variable

This commit is contained in:
dogeystamp 2024-10-25 22:02:30 -04:00
parent a36aa3b0c6
commit 3dac0e4388
3 changed files with 38 additions and 30 deletions

View File

@ -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"; 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); parse_space_and_goto!(FenState::HalfMove);
} }
'a'..='h' => { '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; parser_state = FenState::EnPassantFile;
} }
_ => return bad_char!(i, c), _ => return bad_char!(i, c),
@ -188,8 +188,8 @@ impl FromFen for Board {
FenState::EnPassantFile => { FenState::EnPassantFile => {
if let Some(digit) = c.to_digit(10) { if let Some(digit) = c.to_digit(10) {
pos.ep_square = Some(Square( pos.ep_square = Some(Square(
usize::from(pos.ep_square.unwrap_or(Square(0))) SquareIdx::from(pos.ep_square.unwrap_or(Square(0)))
+ (digit as usize - 1) * 8, + (digit as SquareIdx - 1) * 8,
)); ));
} else { } else {
return bad_char!(i, c); 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 fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1";
let board = Board::from_fen(fen.into()).unwrap(); let board = Board::from_fen(fen.into()).unwrap();
assert_eq!( assert_eq!(
(0..N_SQUARES) (0..SquareIdx::try_from(N_SQUARES).unwrap())
.map(Square) .map(Square)
.map(|i| board.get_piece(i)) .map(|i| board.get_piece(i))
.map(ColPiece::opt_to_char) .map(ColPiece::opt_to_char)

View File

@ -109,11 +109,13 @@ impl ColPiece {
} }
} }
type SquareIdx = u8;
/// Square index newtype. /// Square index newtype.
/// ///
/// A1 is (0, 0) -> 0, A2 is (0, 1) -> 2, and H8 is (7, 7) -> 63. /// 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Square(usize); pub struct Square(SquareIdx);
#[derive(Debug)] #[derive(Debug)]
pub enum SquareError { pub enum SquareError {
@ -121,11 +123,11 @@ pub enum SquareError {
InvalidCharacter(char), InvalidCharacter(char),
} }
impl TryFrom<usize> for Square { impl TryFrom<SquareIdx> for Square {
type Error = SquareError; type Error = SquareError;
fn try_from(value: usize) -> Result<Self, Self::Error> { fn try_from(value: SquareIdx) -> Result<Self, Self::Error> {
if (0..N_SQUARES).contains(&value) { if (0..N_SQUARES).contains(&value.into()) {
Ok(Square(value)) Ok(Square(value))
} else { } else {
Err(SquareError::OutOfBounds) Err(SquareError::OutOfBounds)
@ -141,7 +143,7 @@ macro_rules! sq_try_from {
fn try_from(value: $T) -> Result<Self, Self::Error> { fn try_from(value: $T) -> Result<Self, Self::Error> {
if let Ok(upper_bound) = <$T>::try_from(N_SQUARES) { if let Ok(upper_bound) = <$T>::try_from(N_SQUARES) {
if (0..upper_bound).contains(&value) { if (0..upper_bound).contains(&value) {
return Ok(Square(value as usize)); return Ok(Square(value as SquareIdx));
} }
} }
Err(SquareError::OutOfBounds) Err(SquareError::OutOfBounds)
@ -150,13 +152,20 @@ macro_rules! sq_try_from {
}; };
} }
sq_try_from!(i8);
sq_try_from!(i32); sq_try_from!(i32);
sq_try_from!(isize); sq_try_from!(isize);
sq_try_from!(i8); sq_try_from!(usize);
impl From<Square> for SquareIdx {
fn from(value: Square) -> Self {
value.0
}
}
impl From<Square> for usize { impl From<Square> for usize {
fn from(value: Square) -> Self { fn from(value: Square) -> Self {
value.0 value.0.into()
} }
} }
@ -181,10 +190,10 @@ impl Square {
} }
fn to_row_col(self) -> (usize, usize) { fn to_row_col(self) -> (usize, usize) {
//! Get row, column from index //! Get row, column from index
let div = self.0 / BOARD_WIDTH; let div = usize::from(self.0) / BOARD_WIDTH;
let rem = self.0 % BOARD_WIDTH; let rem = usize::from(self.0) % BOARD_WIDTH;
assert!(div <= 7); debug_assert!(div <= 7);
assert!(rem <= 7); debug_assert!(rem <= 7);
(div, rem) (div, rem)
} }
fn to_row_col_signed(self) -> (isize, isize) { fn to_row_col_signed(self) -> (isize, isize) {
@ -313,7 +322,7 @@ impl Iterator for BitboardIterator {
None None
} else { } else {
let next_idx = self.remaining.0.trailing_zeros() as usize; 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); self.remaining.off_sq(sq);
Some(sq) Some(sq)
} }
@ -620,10 +629,10 @@ mod tests {
try_type!(i32); try_type!(i32);
try_type!(i8); try_type!(i8);
try_type!(isize); 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 { for tc in good_cases {
macro_rules! try_type { macro_rules! try_type {
($T: ty) => { ($T: ty) => {
@ -635,7 +644,7 @@ mod tests {
try_type!(i32); try_type!(i32);
try_type!(i8); try_type!(i8);
try_type!(isize); try_type!(isize);
try_type!(usize); try_type!(u8);
} }
} }
@ -653,10 +662,7 @@ mod tests {
#[test] #[test]
fn test_bitboard_iteration() { fn test_bitboard_iteration() {
let indices = [ let indices = [0, 5, 17, 24, 34, 39, 42, 45, 49, 50, 63];
0usize, 5usize, 17usize, 24usize, 34usize, 39usize, 42usize, 45usize, 49usize, 50usize,
63usize,
];
let mut bitboard = Bitboard::default(); let mut bitboard = Bitboard::default();

View File

@ -228,8 +228,8 @@ impl Move {
); );
// square to actually capture at // square to actually capture at
let ep_capture = Square::try_from(match pc_src.col { let ep_capture = Square::try_from(match pc_src.col {
Color::White => self.dest.0 - BOARD_WIDTH, Color::White => usize::from(self.dest.0) - BOARD_WIDTH,
Color::Black => self.dest.0 + BOARD_WIDTH, Color::Black => usize::from(self.dest.0) + BOARD_WIDTH,
}) })
.expect("En-passant capture square should be valid"); .expect("En-passant capture square should be valid");
@ -302,14 +302,16 @@ impl Move {
Color::White => { Color::White => {
if self.src == Square(0) { if self.src == Square(0) {
castle.q = false; 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; castle.k = false;
}; };
} }
Color::Black => { 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; 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; castle.k = false;
}; };
} }
@ -722,7 +724,7 @@ pub fn perft(depth: usize, pos: &mut Board) -> usize {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::fen::{ToFen, START_POSITION, FromFen}; use crate::fen::{FromFen, ToFen, START_POSITION};
#[test] #[test]
/// Ensure that bitboard properly reflects captures. /// Ensure that bitboard properly reflects captures.