[bitboard] Fix some random clippy issues

This commit is contained in:
Eryn Wells 2025-05-03 16:03:18 -07:00
parent 867deafd13
commit d5cdf273c8

View file

@ -8,6 +8,9 @@ use forward_ref::{forward_ref_binop, forward_ref_op_assign, forward_ref_unop};
use std::fmt; use std::fmt;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
#[allow(clippy::cast_possible_truncation)]
const SQUARES_NUM: u8 = Square::NUM as u8;
/// A bitfield representation of a chess board that uses the bits of a 64-bit /// A bitfield representation of a chess board that uses the bits of a 64-bit
/// unsigned integer to represent whether a square on the board is occupied. /// unsigned integer to represent whether a square on the board is occupied.
/// Squares are laid out as follows, starting at the bottom left, going row-wise, /// Squares are laid out as follows, starting at the bottom left, going row-wise,
@ -103,21 +106,21 @@ impl BitBoard {
} }
impl BitBoard { impl BitBoard {
/// Converts this [BitBoard] to an unsigned 64-bit integer. /// Converts this [`BitBoard`] to an unsigned 64-bit integer.
#[must_use] #[must_use]
pub const fn as_bits(&self) -> u64 { pub const fn as_bits(&self) -> u64 {
self.0 self.0
} }
/// Returns `true` if this [BitBoard] has no bits set. This is the opposite /// Returns `true` if this [`BitBoard`] has no bits set. This is the opposite
/// of [`BitBoard::is_populated`]. /// of [`BitBoard::is_populated`].
/// ///
/// ## Examples /// ## Examples
/// ///
/// ``` /// ```
/// use chessfriend_bitboard::BitBoard; /// use chessfriend_bitboard::BitBoard;
/// assert!(BitBoard::EMPTY.is_empty()); /// assert!(BitBoard::empty().is_empty());
/// assert!(!BitBoard::FULL.is_empty()); /// assert!(!BitBoard::full().is_empty());
/// assert!(!BitBoard::new(0b1000).is_empty()); /// assert!(!BitBoard::new(0b1000).is_empty());
/// ``` /// ```
#[must_use] #[must_use]
@ -125,17 +128,18 @@ impl BitBoard {
self.0 == 0 self.0 == 0
} }
/// Returns `true` if the [BitBoard] has at least one bit set. This is the /// Returns `true` if the [`BitBoard`] has at least one bit set. This is the
/// opposite of [`BitBoard::is_empty`]. /// opposite of [`BitBoard::is_empty`].
/// ///
/// ## Examples /// ## Examples
/// ///
/// ``` /// ```
/// use chessfriend_bitboard::BitBoard; /// use chessfriend_bitboard::BitBoard;
/// assert!(!BitBoard::EMPTY.is_populated()); /// assert!(!BitBoard::empty().is_populated());
/// assert!(BitBoard::FULL.is_populated()); /// assert!(BitBoard::full().is_populated());
/// assert!(BitBoard::new(0b1).is_populated()); /// assert!(BitBoard::new(0b1).is_populated());
/// ``` /// ```
#[must_use]
pub const fn is_populated(&self) -> bool { pub const fn is_populated(&self) -> bool {
self.0 != 0 self.0 != 0
} }
@ -154,21 +158,23 @@ impl BitBoard {
/// assert!(bitboard.contains(Square::C1)); /// assert!(bitboard.contains(Square::C1));
/// assert!(!bitboard.contains(Square::B1)); /// assert!(!bitboard.contains(Square::B1));
/// ``` /// ```
#[must_use]
pub fn contains(self, square: Square) -> bool { pub fn contains(self, square: Square) -> bool {
let square_bitboard: BitBoard = square.into(); let square_bitboard: BitBoard = square.into();
!(self & square_bitboard).is_empty() !(self & square_bitboard).is_empty()
} }
/// Counts the number of set squares (1 bits) in this [BitBoard]. /// Counts the number of set squares (1 bits) in this [`BitBoard`].
/// ///
/// ## Examples /// ## Examples
/// ///
/// ``` /// ```
/// use chessfriend_bitboard::BitBoard; /// use chessfriend_bitboard::BitBoard;
/// assert_eq!(BitBoard::EMPTY.population_count(), 0); /// assert_eq!(BitBoard::empty().population_count(), 0);
/// assert_eq!(BitBoard::new(0b01011110010).population_count(), 6); /// assert_eq!(BitBoard::new(0b01011110010).population_count(), 6);
/// assert_eq!(BitBoard::FULL.population_count(), 64); /// assert_eq!(BitBoard::full().population_count(), 64);
/// ``` /// ```
#[must_use]
pub const fn population_count(&self) -> u32 { pub const fn population_count(&self) -> u32 {
self.0.count_ones() self.0.count_ones()
} }
@ -188,10 +194,10 @@ impl BitBoard {
/// ``` /// ```
pub fn set(&mut self, square: Square) { pub fn set(&mut self, square: Square) {
let square_bitboard: BitBoard = square.into(); let square_bitboard: BitBoard = square.into();
self.0 |= square_bitboard.0 self.0 |= square_bitboard.0;
} }
/// Clear a square (set it to 0) in this [BitBoard]. This always succeeds /// Clear a square (set it to 0) in this [`BitBoard`]. This always succeeds
/// even if the bit is not set. /// even if the bit is not set.
/// ///
/// ## Examples /// ## Examples
@ -206,20 +212,21 @@ impl BitBoard {
/// ``` /// ```
pub fn clear(&mut self, square: Square) { pub fn clear(&mut self, square: Square) {
let square_bitboard: BitBoard = square.into(); let square_bitboard: BitBoard = square.into();
self.0 &= !square_bitboard.0 self.0 &= !square_bitboard.0;
} }
/// Returns `true` if this BitBoard represents a single square. /// Returns `true` if this [`BitBoard`] represents a single square.
/// ///
/// ## Examples /// ## Examples
/// ///
/// ``` /// ```
/// use chessfriend_bitboard::BitBoard; /// use chessfriend_bitboard::BitBoard;
/// assert!(!BitBoard::EMPTY.is_single_square(), "Empty bitboards represent no squares"); /// assert!(!BitBoard::empty().is_single_square(), "Empty bitboards represent no squares");
/// assert!(!BitBoard::FULL.is_single_square(), "Full bitboards represent all the squares"); /// assert!(!BitBoard::full().is_single_square(), "Full bitboards represent all the squares");
/// assert!(!BitBoard::new(0b010011110101101100).is_single_square(), "This bitboard represents a bunch of squares"); /// assert!(!BitBoard::new(0b010011110101101100).is_single_square(), "This bitboard represents a bunch of squares");
/// assert!(BitBoard::new(0b10000000000000).is_single_square()); /// assert!(BitBoard::new(0b10000000000000).is_single_square());
/// ``` /// ```
#[must_use]
pub fn is_single_square(&self) -> bool { pub fn is_single_square(&self) -> bool {
self.0.is_power_of_two() self.0.is_power_of_two()
} }
@ -228,8 +235,9 @@ impl BitBoard {
#[must_use] #[must_use]
pub fn occupied_squares( pub fn occupied_squares(
&self, &self,
direction: IterationDirection, direction: &IterationDirection,
) -> Box<dyn Iterator<Item = Square>> { ) -> Box<dyn Iterator<Item = Square>> {
#[allow(clippy::cast_possible_truncation)]
fn index_to_square(index: usize) -> Square { fn index_to_square(index: usize) -> Square {
unsafe { Square::from_index_unchecked(index as u8) } unsafe { Square::from_index_unchecked(index as u8) }
} }
@ -245,7 +253,7 @@ impl BitBoard {
} }
#[must_use] #[must_use]
pub fn first_occupied_square(&self, direction: IterationDirection) -> Option<Square> { pub fn first_occupied_square(&self, direction: &IterationDirection) -> Option<Square> {
match direction { match direction {
IterationDirection::Leading => self.first_occupied_square_leading(), IterationDirection::Leading => self.first_occupied_square_leading(),
IterationDirection::Trailing => self.first_occupied_square_trailing(), IterationDirection::Trailing => self.first_occupied_square_trailing(),
@ -256,12 +264,12 @@ impl BitBoard {
/// board, starting at the leading (most-significant) end of the board. If /// board, starting at the leading (most-significant) end of the board. If
/// the board is empty, returns `None`. /// the board is empty, returns `None`.
#[must_use] #[must_use]
fn first_occupied_square_leading(&self) -> Option<Square> { fn first_occupied_square_leading(self) -> Option<Square> {
let leading_zeros = self.0.leading_zeros() as u8; let leading_zeros = self._leading_zeros();
if leading_zeros < Square::NUM as u8 { if leading_zeros < SQUARES_NUM {
unsafe { unsafe {
Some(Square::from_index_unchecked( Some(Square::from_index_unchecked(
Square::NUM as u8 - leading_zeros - 1, SQUARES_NUM - leading_zeros - 1,
)) ))
} }
} else { } else {
@ -273,9 +281,10 @@ impl BitBoard {
/// board, starting at the trailing (least-significant) end of the board. /// board, starting at the trailing (least-significant) end of the board.
/// If the board is empty, returns `None`. /// If the board is empty, returns `None`.
#[must_use] #[must_use]
fn first_occupied_square_trailing(&self) -> Option<Square> { fn first_occupied_square_trailing(self) -> Option<Square> {
let trailing_zeros = self.0.trailing_zeros() as u8; let trailing_zeros = self._trailing_zeros();
if trailing_zeros < Square::NUM as u8 {
if trailing_zeros < SQUARES_NUM {
unsafe { Some(Square::from_index_unchecked(trailing_zeros)) } unsafe { Some(Square::from_index_unchecked(trailing_zeros)) }
} else { } else {
None None
@ -283,6 +292,20 @@ impl BitBoard {
} }
} }
impl BitBoard {
#[must_use]
#[allow(clippy::cast_possible_truncation)]
fn _leading_zeros(self) -> u8 {
self.0.leading_zeros() as u8
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
fn _trailing_zeros(self) -> u8 {
self.0.trailing_zeros() as u8
}
}
impl Default for BitBoard { impl Default for BitBoard {
fn default() -> Self { fn default() -> Self {
BitBoard::EMPTY BitBoard::EMPTY
@ -341,7 +364,7 @@ impl TryFrom<BitBoard> for Square {
return Err(TryFromBitBoardError::NotSingleSquare); return Err(TryFromBitBoardError::NotSingleSquare);
} }
unsafe { Ok(Square::from_index_unchecked(value.0.trailing_zeros() as u8)) } unsafe { Ok(Square::from_index_unchecked(value._trailing_zeros())) }
} }
} }
@ -376,8 +399,7 @@ impl fmt::Display for BitBoard {
let mut ranks_written = 0; let mut ranks_written = 0;
for rank in binary_ranks.chunks(8).rev() { for rank in binary_ranks.chunks(8).rev() {
let joined_rank = rank.join(" "); write!(f, "{}", rank.join(" "))?;
write!(f, "{}", joined_rank)?;
ranks_written += 1; ranks_written += 1;
if ranks_written < 8 { if ranks_written < 8 {
@ -456,6 +478,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::unreadable_literal)]
fn rank() { fn rank() {
assert_eq!(BitBoard::rank(&0).0, 0xFF, "Rank 1"); assert_eq!(BitBoard::rank(&0).0, 0xFF, "Rank 1");
assert_eq!(BitBoard::rank(&1).0, 0xFF00, "Rank 2"); assert_eq!(BitBoard::rank(&1).0, 0xFF00, "Rank 2");
@ -469,11 +492,13 @@ mod tests {
#[test] #[test]
fn single_rank_occupancy() { fn single_rank_occupancy() {
#[allow(clippy::unreadable_literal)]
let bb = BitBoard(0b01010100); let bb = BitBoard(0b01010100);
let expected_squares = [Square::G1, Square::E1, Square::C1]; let expected_squares = [Square::G1, Square::E1, Square::C1];
for (a, b) in bb for (a, b) in bb
.occupied_squares(IterationDirection::Leading) .occupied_squares(&IterationDirection::Leading)
.zip(expected_squares.iter().cloned()) .zip(expected_squares.iter().copied())
{ {
assert_eq!(a, b); assert_eq!(a, b);
} }
@ -481,13 +506,14 @@ mod tests {
#[test] #[test]
fn occupancy_spot_check() { fn occupancy_spot_check() {
#[allow(clippy::unreadable_literal)]
let bb = let bb =
BitBoard(0b10000000_00000000_00100000_00000100_00000000_00000000_00010000_00001000); BitBoard(0b10000000_00000000_00100000_00000100_00000000_00000000_00010000_00001000);
let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1]; let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1];
for (a, b) in bb for (a, b) in bb
.occupied_squares(IterationDirection::Leading) .occupied_squares(&IterationDirection::Leading)
.zip(expected_squares.iter().cloned()) .zip(expected_squares.iter().cloned())
{ {
assert_eq!(a, b); assert_eq!(a, b);