[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::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
/// 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,
@ -103,21 +106,21 @@ impl BitBoard {
}
impl BitBoard {
/// Converts this [BitBoard] to an unsigned 64-bit integer.
/// Converts this [`BitBoard`] to an unsigned 64-bit integer.
#[must_use]
pub const fn as_bits(&self) -> u64 {
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`].
///
/// ## Examples
///
/// ```
/// use chessfriend_bitboard::BitBoard;
/// assert!(BitBoard::EMPTY.is_empty());
/// assert!(!BitBoard::FULL.is_empty());
/// assert!(BitBoard::empty().is_empty());
/// assert!(!BitBoard::full().is_empty());
/// assert!(!BitBoard::new(0b1000).is_empty());
/// ```
#[must_use]
@ -125,17 +128,18 @@ impl BitBoard {
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`].
///
/// ## Examples
///
/// ```
/// use chessfriend_bitboard::BitBoard;
/// assert!(!BitBoard::EMPTY.is_populated());
/// assert!(BitBoard::FULL.is_populated());
/// assert!(!BitBoard::empty().is_populated());
/// assert!(BitBoard::full().is_populated());
/// assert!(BitBoard::new(0b1).is_populated());
/// ```
#[must_use]
pub const fn is_populated(&self) -> bool {
self.0 != 0
}
@ -154,21 +158,23 @@ impl BitBoard {
/// assert!(bitboard.contains(Square::C1));
/// assert!(!bitboard.contains(Square::B1));
/// ```
#[must_use]
pub fn contains(self, square: Square) -> bool {
let square_bitboard: BitBoard = square.into();
!(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
///
/// ```
/// 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::FULL.population_count(), 64);
/// assert_eq!(BitBoard::full().population_count(), 64);
/// ```
#[must_use]
pub const fn population_count(&self) -> u32 {
self.0.count_ones()
}
@ -188,10 +194,10 @@ impl BitBoard {
/// ```
pub fn set(&mut self, square: Square) {
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.
///
/// ## Examples
@ -206,20 +212,21 @@ impl BitBoard {
/// ```
pub fn clear(&mut self, square: Square) {
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
///
/// ```
/// use chessfriend_bitboard::BitBoard;
/// 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::empty().is_single_square(), "Empty bitboards represent no 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(0b10000000000000).is_single_square());
/// ```
#[must_use]
pub fn is_single_square(&self) -> bool {
self.0.is_power_of_two()
}
@ -228,8 +235,9 @@ impl BitBoard {
#[must_use]
pub fn occupied_squares(
&self,
direction: IterationDirection,
direction: &IterationDirection,
) -> Box<dyn Iterator<Item = Square>> {
#[allow(clippy::cast_possible_truncation)]
fn index_to_square(index: usize) -> Square {
unsafe { Square::from_index_unchecked(index as u8) }
}
@ -245,7 +253,7 @@ impl BitBoard {
}
#[must_use]
pub fn first_occupied_square(&self, direction: IterationDirection) -> Option<Square> {
pub fn first_occupied_square(&self, direction: &IterationDirection) -> Option<Square> {
match direction {
IterationDirection::Leading => self.first_occupied_square_leading(),
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
/// the board is empty, returns `None`.
#[must_use]
fn first_occupied_square_leading(&self) -> Option<Square> {
let leading_zeros = self.0.leading_zeros() as u8;
if leading_zeros < Square::NUM as u8 {
fn first_occupied_square_leading(self) -> Option<Square> {
let leading_zeros = self._leading_zeros();
if leading_zeros < SQUARES_NUM {
unsafe {
Some(Square::from_index_unchecked(
Square::NUM as u8 - leading_zeros - 1,
SQUARES_NUM - leading_zeros - 1,
))
}
} else {
@ -273,9 +281,10 @@ impl BitBoard {
/// board, starting at the trailing (least-significant) end of the board.
/// If the board is empty, returns `None`.
#[must_use]
fn first_occupied_square_trailing(&self) -> Option<Square> {
let trailing_zeros = self.0.trailing_zeros() as u8;
if trailing_zeros < Square::NUM as u8 {
fn first_occupied_square_trailing(self) -> Option<Square> {
let trailing_zeros = self._trailing_zeros();
if trailing_zeros < SQUARES_NUM {
unsafe { Some(Square::from_index_unchecked(trailing_zeros)) }
} else {
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 {
fn default() -> Self {
BitBoard::EMPTY
@ -341,7 +364,7 @@ impl TryFrom<BitBoard> for Square {
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;
for rank in binary_ranks.chunks(8).rev() {
let joined_rank = rank.join(" ");
write!(f, "{}", joined_rank)?;
write!(f, "{}", rank.join(" "))?;
ranks_written += 1;
if ranks_written < 8 {
@ -456,6 +478,7 @@ mod tests {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn rank() {
assert_eq!(BitBoard::rank(&0).0, 0xFF, "Rank 1");
assert_eq!(BitBoard::rank(&1).0, 0xFF00, "Rank 2");
@ -469,11 +492,13 @@ mod tests {
#[test]
fn single_rank_occupancy() {
#[allow(clippy::unreadable_literal)]
let bb = BitBoard(0b01010100);
let expected_squares = [Square::G1, Square::E1, Square::C1];
for (a, b) in bb
.occupied_squares(IterationDirection::Leading)
.zip(expected_squares.iter().cloned())
.occupied_squares(&IterationDirection::Leading)
.zip(expected_squares.iter().copied())
{
assert_eq!(a, b);
}
@ -481,13 +506,14 @@ mod tests {
#[test]
fn occupancy_spot_check() {
#[allow(clippy::unreadable_literal)]
let bb =
BitBoard(0b10000000_00000000_00100000_00000100_00000000_00000000_00010000_00001000);
let expected_squares = [Square::H8, Square::F6, Square::C5, Square::E2, Square::D1];
for (a, b) in bb
.occupied_squares(IterationDirection::Leading)
.occupied_squares(&IterationDirection::Leading)
.zip(expected_squares.iter().cloned())
{
assert_eq!(a, b);