refactor: use Index/IndexMut instead of helper functions

This commit is contained in:
dogeystamp 2024-11-01 21:46:53 -04:00
parent 8d5ea3de31
commit 60d084886f
3 changed files with 62 additions and 53 deletions

View File

@ -41,8 +41,8 @@ impl Eval for Board {
];
for pc in [Rook, Queen, Pawn, Knight, Bishop, King] {
let tally_white = self.pl(Color::White).board(pc).0.count_ones();
let tally_black = self.pl(Color::Black).board(pc).0.count_ones();
let tally_white = self[Color::White][pc].0.count_ones();
let tally_black = self[Color::Black][pc].0.count_ones();
let tally =
EvalInt::try_from(tally_white).unwrap() - EvalInt::try_from(tally_black).unwrap();

View File

@ -14,6 +14,7 @@ Copyright © 2024 dogeystamp <dogeystamp@disroot.org>
#![deny(rust_2018_idioms)]
use std::fmt::Display;
use std::ops::{Index, IndexMut};
use std::str::FromStr;
pub mod eval;
@ -372,23 +373,11 @@ impl Mailbox {
///
/// Default is all empty.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
struct Player {
pub struct PlayerBoards {
/// Bitboards for individual pieces. Piece -> locations.
bit: [Bitboard; N_PIECES],
}
impl Player {
/// Get board (non-mutable) for a specific piece.
fn board(&self, pc: Piece) -> &Bitboard {
&self.bit[pc as usize]
}
/// Get board (mutable) for a specific piece.
fn board_mut(&mut self, pc: Piece) -> &mut Bitboard {
&mut self.bit[pc as usize]
}
}
/// Castling rights for one player
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub struct CastlePlayer {
@ -402,9 +391,9 @@ pub struct CastlePlayer {
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub struct CastleRights([CastlePlayer; N_COLORS]);
impl ToString for CastleRights {
impl Display for CastleRights {
/// Convert to FEN castling rights format.
fn to_string(&self) -> String {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ret = String::with_capacity(4);
for (val, ch) in [
(self.0[Color::White as usize].k, 'K'),
@ -419,7 +408,7 @@ impl ToString for CastleRights {
if ret.is_empty() {
ret.push('-')
}
ret
write!(f, "{}", ret)
}
}
@ -429,7 +418,7 @@ impl ToString for CastleRights {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Board {
/// Player bitboards
players: [Player; N_COLORS],
players: [PlayerBoards; N_COLORS],
/// Mailbox (array) board. Location -> piece.
mail: Mailbox,
@ -458,26 +447,6 @@ impl Board {
Board::from_fen(START_POSITION).unwrap()
}
/// Get mutable reference to a player.
fn pl_mut(&mut self, col: Color) -> &mut Player {
&mut self.players[col as usize]
}
/// Get immutable reference to a player.
fn pl(&self, col: Color) -> &Player {
&self.players[col as usize]
}
/// Get immutable reference to castling rights.
pub fn pl_castle(&self, col: Color) -> &CastlePlayer {
&self.castle.0[col as usize]
}
/// Get mutable reference to castling rights.
fn pl_castle_mut(&mut self, col: Color) -> &mut CastlePlayer {
&mut self.castle.0[col as usize]
}
/// Get iterator over all squares.
pub fn squares() -> impl Iterator<Item = Square> {
(0..N_SQUARES).map(Square::try_from).map(|x| x.unwrap())
@ -486,8 +455,8 @@ impl Board {
/// Create a new piece in a location, and pop any existing piece in the destination.
pub fn set_piece(&mut self, idx: Square, pc: ColPiece) -> Option<ColPiece> {
let dest_pc = self.del_piece(idx);
let pl = self.pl_mut(pc.col);
pl.board_mut(pc.into()).on_sq(idx);
let pl = &mut self[pc.col];
pl[pc.into()].on_sq(idx);
*self.mail.sq_mut(idx) = Some(pc);
dest_pc
}
@ -503,8 +472,8 @@ impl Board {
/// Delete the piece in a location, and return ("pop") that piece.
pub fn del_piece(&mut self, idx: Square) -> Option<ColPiece> {
if let Some(pc) = *self.mail.sq_mut(idx) {
let pl = self.pl_mut(pc.col);
pl.board_mut(pc.into()).off_sq(idx);
let pl = &mut self[pc.col];
pl[pc.into()].off_sq(idx);
*self.mail.sq_mut(idx) = None;
Some(pc)
} else {
@ -555,7 +524,7 @@ impl Board {
/// Is a given player in check?
pub fn is_check(&self, pl: Color) -> bool {
for src in self.pl(pl).board(Piece::King).into_iter() {
for src in self[pl][Piece::King] {
macro_rules! detect_checker {
($dirs: ident, $pc: pat, $keep_going: expr) => {
for dir in $dirs.into_iter() {
@ -606,6 +575,48 @@ impl Board {
const MAX_MOVES: usize = 9_999;
}
impl Index<Color> for Board {
type Output = PlayerBoards;
fn index(&self, col: Color) -> &Self::Output {
&self.players[col as usize]
}
}
impl IndexMut<Color> for Board {
fn index_mut(&mut self, col: Color) -> &mut Self::Output {
&mut self.players[col as usize]
}
}
impl Index<Color> for CastleRights {
type Output = CastlePlayer;
fn index(&self, col: Color) -> &Self::Output {
&self.0[col as usize]
}
}
impl IndexMut<Color> for CastleRights {
fn index_mut(&mut self, col: Color) -> &mut Self::Output {
&mut self.0[col as usize]
}
}
impl Index<Piece> for PlayerBoards {
type Output = Bitboard;
fn index(&self, pc: Piece) -> &Self::Output {
&self.bit[pc as usize]
}
}
impl IndexMut<Piece> for PlayerBoards {
fn index_mut(&mut self, pc: Piece) -> &mut Self::Output {
&mut self.bit[pc as usize]
}
}
impl core::fmt::Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut str = String::with_capacity(N_SQUARES + BOARD_HEIGHT);
@ -693,9 +704,7 @@ mod tests {
}
let board = Board::from_fen("8/4p3/1q1Q1p2/4p3/1p1r4/8/8/8 w - - 0 1").unwrap();
let white_queens = board
.pl(Color::White)
.board(Piece::Queen)
let white_queens = board[Color::White][Piece::Queen]
.into_iter()
.collect::<Vec<Square>>();
assert_eq!(white_queens, vec![Square::from_str("d6").unwrap()])

View File

@ -296,7 +296,7 @@ impl Move {
pos.half_moves = 0;
}
let castle = &mut pos.pl_castle_mut(pc_src.col);
let castle = &mut pos.castle[pc_src.col];
if matches!(pc_src.pc, Piece::King) {
// forfeit castling rights
castle.k = false;
@ -564,10 +564,10 @@ fn is_legal(board: &mut Board, mv: Move) -> bool {
impl MoveGen for Board {
fn gen_moves(&mut self, gen_type: MoveGenType) -> impl IntoIterator<Item = Move> {
let mut ret = Vec::new();
let pl = self.pl(self.turn);
let pl = self[self.turn];
macro_rules! squares {
($pc: ident) => {
pl.board(Piece::$pc).into_iter()
pl[Piece::$pc].into_iter()
};
}
@ -583,7 +583,7 @@ impl MoveGen for Board {
for src in squares!(King) {
move_slider(self, src, &mut ret, SliderDirection::Star, false);
let (r, c) = src.to_row_col_signed();
let rights = self.pl_castle(self.turn);
let rights = self.castle[self.turn];
let castle_sides = [(rights.k, 2, BOARD_WIDTH as isize - 1), (rights.q, -2, 0)];
for (is_allowed, move_offset, endpoint) in castle_sides {
if !is_allowed {
@ -784,8 +784,8 @@ mod tests {
use std::collections::hash_set::HashSet;
use Piece::*;
for pc in [Rook, Bishop, Knight, Queen, King, Pawn] {
let white: HashSet<_> = pos.pl(Color::White).board(pc).into_iter().collect();
let black: HashSet<_> = pos.pl(Color::Black).board(pc).into_iter().collect();
let white: HashSet<_> = pos[Color::White][pc].into_iter().collect();
let black: HashSet<_> = pos[Color::Black][pc].into_iter().collect();
let intersect = white.intersection(&black).collect::<Vec<_>>();
assert!(
intersect.is_empty(),