Skip to content

Commit

Permalink
chore: ad some utility types
Browse files Browse the repository at this point in the history
  • Loading branch information
raklaptudirm committed Sep 8, 2024
1 parent 53eb856 commit 702add5
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 170 deletions.
175 changes: 10 additions & 165 deletions games/src/interface/bitboard.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use num_traits::int::PrimInt;
use std::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr, Sub};

use super::{RepresentableType, SquareType};
use super::{File, PositionType, RepresentableType, SquareType};

pub type BitBoard<T> = <T as PositionType>::BitBoard;

/// BitBoardType is a generalized interface implemented by BitBoards of
/// arbitrary size. This allows programs to handle BitBoards of any size with
Expand Down Expand Up @@ -76,28 +78,27 @@ where

/// north returns a new Self with all the squares shifted to the north.
fn north(self) -> Self {
(self << <Self::Square as SquareType>::File::N) & Self::UNIVERSE
(self << File::<Self::Square>::N) & Self::UNIVERSE
}

/// south returns a new Self with all the squares shifted to the south.
fn south(self) -> Self {
self >> <Self::Square as SquareType>::File::N
self >> File::<Self::Square>::N
}

/// east returns a new Self with all the squares shifted to the east.
fn east(self) -> Self {
(self << 1)
& (Self::UNIVERSE
^ unsafe { Self::file(<Self::Square as SquareType>::File::unsafe_from(0u8)) })
& (Self::UNIVERSE ^ unsafe { Self::file(File::<Self::Square>::unsafe_from(0u8)) })
}

/// west returns a new Self with all the squares shifted to the west.
fn west(self) -> Self {
(self >> 1)
& (Self::UNIVERSE
^ unsafe {
Self::file(<Self::Square as SquareType>::File::unsafe_from(
<Self::Square as SquareType>::File::N as u8 - 1,
Self::file(File::<Self::Square>::unsafe_from(
File::<Self::Square>::N as u8 - 1,
))
})
}
Expand Down Expand Up @@ -174,168 +175,12 @@ where
}

/// Returns a BitBoard containing all the squares from the given `File`.
fn file(file: <Self::Square as SquareType>::File) -> Self {
fn file(file: File<Self::Square>) -> Self {
Self::FIRST_FILE << file.into() as usize
}

/// Returns a BitBoard containing all the squares from the given `Rank`.
fn rank(rank: <Self::Square as SquareType>::Rank) -> Self {
Self::FIRST_RANK << (<Self::Square as SquareType>::File::N * rank.into() as usize)
Self::FIRST_RANK << (File::<Self::Square>::N * rank.into() as usize)
}
}

/// bitboard_type generates a new BitBoard with the given type as its base
/// representation. The base type must implement num_traits::int::PrimInt so
/// that the BitBoardType trait can be implemented.
///
/// # Examples
///
/// ```
/// bitboard_type! {
/// BitBoardTypeName: u64 {
/// Square = OurSquareType;
/// Empty = OurEmptyBitBoard;
/// Universe = OurUniverseBitBoard;
/// FirstFile = OurFirstFileBitBoard;
/// FirstRank = OurFirstRankBitBoard;
/// }
/// }
/// ```
macro_rules! bitboard_type {
($name:tt : $typ:tt {
Square = $sq:tt;
Empty = $empty:expr;
Universe = $universe:expr;
FirstFile = $first_file:expr;
FirstRank = $first_rank:expr;
} ) => {
#[derive(
Copy,
Clone,
PartialEq,
Eq,
num_derive::FromPrimitive,
derive_more::BitOr,
derive_more::BitAnd,
derive_more::BitXor,
derive_more::Shl,
derive_more::Shr,
derive_more::BitAndAssign,
derive_more::BitOrAssign,
derive_more::BitXorAssign,
derive_more::ShlAssign,
derive_more::ShrAssign,
derive_more::SubAssign,
)]
pub struct $name(pub $typ);

impl $crate::interface::BitBoardType for $name {
type Base = $typ;
type Square = $sq;

const EMPTY: Self = $empty;
const UNIVERSE: Self = $universe;
const FIRST_FILE: Self = $first_file;
const FIRST_RANK: Self = $first_rank;
}

impl Iterator for $name {
type Item = $sq;

/// next pops the next Square from the BitBoard and returns it.
fn next(&mut self) -> Option<Self::Item> {
$crate::interface::BitBoardType::pop_lsb(self)
}
}

impl std::ops::Sub<usize> for $name {
type Output = Self;

fn sub(self, rhs: usize) -> Self::Output {
Self(self.0 - rhs as u64)
}
}

impl From<$typ> for $name {
fn from(num: $typ) -> Self {
Self(num)
}
}

impl From<$name> for $typ {
fn from(value: $name) -> Self {
value.0
}
}

impl From<$sq> for $name {
fn from(square: $sq) -> Self {
Self(1 << square as u64)
}
}

impl std::ops::Not for $name {
type Output = Self;

/// Returns the complementary BitBoard of `self`.
fn not(self) -> Self::Output {
// ! will set the unused bits so remove them with an &.
Self(!self.0) & <Self as $crate::interface::BitBoardType>::UNIVERSE
}
}

#[allow(clippy::suspicious_arithmetic_impl)]
impl std::ops::Sub for $name {
type Output = Self;

/// Returns the difference of `self` and `rhs` as a new BitBoard.
fn sub(self, rhs: Self) -> Self::Output {
self & !rhs
}
}

#[allow(clippy::suspicious_arithmetic_impl)]
impl std::ops::BitOr<$sq> for $name {
type Output = Self;

/// Returns the union of `self` and `rhs` as a new BitBoard.
fn bitor(self, rhs: $sq) -> Self::Output {
self | Self::from(rhs)
}
}

impl std::ops::Sub<$sq> for $name {
type Output = Self;

/// Returns the BitBoard obtained on removing `rhs` from `self`.
fn sub(self, rhs: $sq) -> Self::Output {
self & !Self::from(rhs)
}
}

// Display a bitboard as ASCII art with 0s and 1s.
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut string_rep = String::from("");
for rank in <<$sq as $crate::interface::SquareType>::Rank as strum::IntoEnumIterator>::iter().rev() {
for file in <<$sq as $crate::interface::SquareType>::File as strum::IntoEnumIterator>::iter() {
let square = <$sq as $crate::interface::SquareType>::new(file, rank);
string_rep += if $crate::interface::BitBoardType::contains(*self, square) { "1 " } else { "0 " };
}

string_rep += "\n";
}

write!(f, "{string_rep}")
}
}

impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
};
}

pub(crate) use bitboard_type;
160 changes: 157 additions & 3 deletions games/src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ mod piece;
mod position;
mod square;

pub use bitboard::BitBoardType;
pub use bitboard::*;
pub use hash::*;
pub use piece::*;
pub use position::*;
pub use r#move::*;
pub use square::*;

pub(crate) use bitboard::bitboard_type;

/// RepresentableType is a basic trait which is implemented by enums with both a
/// binary and string representation and backed by an integer.
pub trait RepresentableType<B: Into<usize>>:
Expand Down Expand Up @@ -98,3 +96,159 @@ macro_rules! representable_type {
}

pub(crate) use representable_type;

/// bitboard_type generates a new BitBoard with the given type as its base
/// representation. The base type must implement num_traits::int::PrimInt so
/// that the BitBoardType trait can be implemented.
///
/// # Examples
///
/// ```
/// bitboard_type! {
/// BitBoardTypeName: u64 {
/// Square = OurSquareType;
/// Empty = OurEmptyBitBoard;
/// Universe = OurUniverseBitBoard;
/// FirstFile = OurFirstFileBitBoard;
/// FirstRank = OurFirstRankBitBoard;
/// }
/// }
/// ```
macro_rules! bitboard_type {
($name:tt : $typ:tt {
Square = $sq:tt;
Empty = $empty:expr;
Universe = $universe:expr;
FirstFile = $first_file:expr;
FirstRank = $first_rank:expr;
} ) => {
#[derive(
Copy,
Clone,
PartialEq,
Eq,
num_derive::FromPrimitive,
derive_more::BitOr,
derive_more::BitAnd,
derive_more::BitXor,
derive_more::Shl,
derive_more::Shr,
derive_more::BitAndAssign,
derive_more::BitOrAssign,
derive_more::BitXorAssign,
derive_more::ShlAssign,
derive_more::ShrAssign,
derive_more::SubAssign,
)]
pub struct $name(pub $typ);

impl $crate::interface::BitBoardType for $name {
type Base = $typ;
type Square = $sq;

const EMPTY: Self = $empty;
const UNIVERSE: Self = $universe;
const FIRST_FILE: Self = $first_file;
const FIRST_RANK: Self = $first_rank;
}

impl Iterator for $name {
type Item = $sq;

/// next pops the next Square from the BitBoard and returns it.
fn next(&mut self) -> Option<Self::Item> {
$crate::interface::BitBoardType::pop_lsb(self)
}
}

impl std::ops::Sub<usize> for $name {
type Output = Self;

fn sub(self, rhs: usize) -> Self::Output {
Self(self.0 - rhs as u64)
}
}

impl From<$typ> for $name {
fn from(num: $typ) -> Self {
Self(num)
}
}

impl From<$name> for $typ {
fn from(value: $name) -> Self {
value.0
}
}

impl From<$sq> for $name {
fn from(square: $sq) -> Self {
Self(1 << square as u64)
}
}

impl std::ops::Not for $name {
type Output = Self;

/// Returns the complementary BitBoard of `self`.
fn not(self) -> Self::Output {
// ! will set the unused bits so remove them with an &.
Self(!self.0) & <Self as $crate::interface::BitBoardType>::UNIVERSE
}
}

#[allow(clippy::suspicious_arithmetic_impl)]
impl std::ops::Sub for $name {
type Output = Self;

/// Returns the difference of `self` and `rhs` as a new BitBoard.
fn sub(self, rhs: Self) -> Self::Output {
self & !rhs
}
}

#[allow(clippy::suspicious_arithmetic_impl)]
impl std::ops::BitOr<$sq> for $name {
type Output = Self;

/// Returns the union of `self` and `rhs` as a new BitBoard.
fn bitor(self, rhs: $sq) -> Self::Output {
self | Self::from(rhs)
}
}

impl std::ops::Sub<$sq> for $name {
type Output = Self;

/// Returns the BitBoard obtained on removing `rhs` from `self`.
fn sub(self, rhs: $sq) -> Self::Output {
self & !Self::from(rhs)
}
}

// Display a bitboard as ASCII art with 0s and 1s.
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut string_rep = String::from("");
for rank in <<$sq as $crate::interface::SquareType>::Rank as strum::IntoEnumIterator>::iter().rev() {
for file in <<$sq as $crate::interface::SquareType>::File as strum::IntoEnumIterator>::iter() {
let square = <$sq as $crate::interface::SquareType>::new(file, rank);
string_rep += if $crate::interface::BitBoardType::contains(*self, square) { "1 " } else { "0 " };
}

string_rep += "\n";
}

write!(f, "{string_rep}")
}
}

impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
};
}

pub(crate) use bitboard_type;
Loading

0 comments on commit 702add5

Please sign in to comment.