refactor: use Index/IndexMut instead of helper functions
This commit is contained in:
parent
8d5ea3de31
commit
60d084886f
@ -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();
|
||||
|
||||
|
99
src/lib.rs
99
src/lib.rs
@ -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()])
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user