From 703170a1e4a125f3837f37e820805a9bd094bbc2 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Mon, 29 Jul 2024 01:42:55 +0530 Subject: [PATCH] fuck this actually compiles hahaha --- games/src/bitboard.rs | 207 ++++++++++++++++++++++++++++++++++++++++++ games/src/lib.rs | 65 ++----------- 2 files changed, 213 insertions(+), 59 deletions(-) create mode 100644 games/src/bitboard.rs diff --git a/games/src/bitboard.rs b/games/src/bitboard.rs new file mode 100644 index 0000000..edd8729 --- /dev/null +++ b/games/src/bitboard.rs @@ -0,0 +1,207 @@ +use std::fmt::Display; +use std::ops::BitOr; +use std::str::FromStr; + +pub trait BitBoard: + Sized + + Copy + + From + + From + + Into + + BitOr + + From<>::Output> +where + >::Output: Into, + Self::Square: Square, +{ + type Square; + + /// EMPTY is an empty Self containing no Squares. + const EMPTY: Self; + + /// UNIVERSE is a filled Self containing all Squares. + const UNIVERSE: Self; + + const FIRST_FILE: Self; + const FIRST_RANK: Self; + + /// is_disjoint checks if the two Selfs are disjoint, i.e. don't have + /// any squares in common among themselves. + fn is_disjoint(self, other: Self) -> bool { + self.into() & other.into() == Self::EMPTY.into() + } + + /// is_subset checks if the given Self is a subset of the target, i.e. + /// all the squares in the target are also present in the given Self. + fn is_subset(self, other: Self) -> bool { + other.into() & !self.into() == Self::EMPTY.into() + } + + /// is_superset checks if the given Self is a superset of the target, i.e. + /// all the squares in the given Self are also present in the target. + /// ``` + /// use ataxx::*; + /// + /// assert!(!Self::UNIVERSE.is_superset(Self::EMPTY)); + /// assert!( Self::EMPTY.is_superset(Self::UNIVERSE)); + /// ``` + fn is_superset(self, other: Self) -> bool { + other.is_subset(self) + } + + /// is_empty checks if the target Self is empty. + fn is_empty(self) -> bool { + self.into() == Self::EMPTY.into() + } + + /// cardinality returns the number of Squares present in the Self. + fn cardinality(self) -> usize { + self.into().count_ones() as usize + } + + /// contains checks if the Self contains the given Self::Square. + fn contains(self, square: Self::Square) -> bool { + self.into() & (1 << square.into()) != Self::EMPTY.into() + } + + /// north returns a new Self with all the squares shifted to the north. + fn north(self) -> Self { + Self::from((self.into() << ::File::N) & Self::UNIVERSE.into()) + } + + /// south returns a new Self with all the squares shifted to the south. + fn south(self) -> Self { + Self::from(self.into() >> ::File::N) + } + + /// east returns a new Self with all the squares shifted to the east. + fn east(self) -> Self { + Self::from( + (self.into() << 1) + & (Self::UNIVERSE.into() + ^ Self::file(::File::from(0)).into()), + ) + } + + /// west returns a new Self with all the squares shifted to the west. + fn west(self) -> Self { + Self::from( + (self.into() >> 1) + & (Self::UNIVERSE.into() + ^ Self::file(::File::from( + ::File::N as u8 - 1, + )) + .into()), + ) + } + + /// insert puts the given Self::Square into the Self. + fn insert(&mut self, square: Self::Square) { + *self = + Self::from(>::into(*self) | Self::from(square).into()) + } + + /// remove removes the given Self::Square from the Self. + fn remove(&mut self, square: Self::Square) { + *self = + Self::from(>::into(*self) & !Self::from(square).into()) + } + + /// pop_lsb pops the least significant Self::Square from the Self, i.e. it + /// removes the lsb from the Self and returns its value. + fn pop_lsb(&mut self) -> Self::Square { + let lsb = self.lsb(); + let copy = >::into(*self); + *self = >::from(copy & (copy - 1)); + + lsb + } + + /// pop_msb pops the most significant Self::Square from the Self i.e. it + /// removes the msb from the Self and returns its value. + fn pop_msb(&mut self) -> Self::Square { + let msb = self.msb(); + *self = Self::from(>::into(*self) ^ Self::from(msb).into()); + + msb + } + + /// get_lsb returns the least significant Self::Square from the Self. + fn lsb(self) -> Self::Square { + Self::Square::unsafe_from(self.into().trailing_zeros() as usize) + } + + /// get_msb returns the most significant Self::Square from the Self. + fn msb(self) -> Self::Square { + Self::Square::unsafe_from(63 - self.into().leading_zeros() as usize) + } + + fn singles(self) -> Self { + let bar: Self = ((self | self.east()).into() | self.west()).into(); + ((bar | bar.north()).into() | bar.south()).into() + } + + /// file returns a Self containing all the squares from the given ::File. + fn file(file: ::File) -> Self { + Self::from(Self::FIRST_FILE.into() << file.into()) + } + + /// rank returns a Self containing all the squares from the given Self::Square::Rank. + fn rank(rank: ::Rank) -> Self { + Self::from( + Self::FIRST_RANK.into() << (::File::N * rank.into() as usize), + ) + } +} + +pub trait Square: RepresentableType +where + Self::File: RepresentableType, + Self::Rank: RepresentableType, +{ + type File; + type Rank; + + fn new(file: Self::File, rank: Self::Rank) -> Self { + Self::unsafe_from(rank.into() * Self::File::N as u8 + file.into()) + } + + fn file(self) -> Self::File { + Self::File::unsafe_from(self.into() % Self::File::N as u8) + } + + fn rank(self) -> Self::Rank { + Self::Rank::unsafe_from(self.into() / Self::File::N as u8) + } + + fn north(self) -> Self { + Self::unsafe_from(self.into() + Self::File::N as u8) + } + + fn south(self) -> Self { + Self::unsafe_from(self.into() - Self::File::N as u8) + } + + fn east(self) -> Self { + Self::unsafe_from(self.into() + 1) + } + + fn west(self) -> Self { + Self::unsafe_from(self.into() - 1) + } +} + +/// 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>: + Copy + Eq + FromStr + Display + From + Into +{ + /// N is the number of specializations of the enum. + const N: usize; + + /// unsafe_from unsafely converts the given number into Self. + fn unsafe_from>(number: T) -> Self { + debug_assert!(number.into() < Self::N); + unsafe { std::mem::transmute_copy(&number) } + } +} diff --git a/games/src/lib.rs b/games/src/lib.rs index 4182d6b..7c9747f 100644 --- a/games/src/lib.rs +++ b/games/src/lib.rs @@ -5,6 +5,8 @@ use std::str::FromStr; use arrayvec::ArrayVec; pub mod ataxx; +mod bitboard; +pub use bitboard::*; /// Position is a generalized interface for board representations of a wide /// range of games. It can be used to create game-agnostic software. Tetka @@ -20,13 +22,10 @@ where >::Output: Into, ::Piece>>::Output: Into, ::Color>>::Output: Into, - Self::Square: Square, - Self::BitBoard: BitBoard, + Self::BitBoard: bitboard::BitBoard, Self::ColoredPiece: ColoredPiece, Self::Move: Move, { - /// The type for the squares used by this board representation. - type Square; /// The type for the bitboards used by this board representation. type BitBoard; @@ -40,11 +39,11 @@ where /// insert puts the given piece at the given square. The implementation is /// free to assume that the square is currently empty. - fn insert(&mut self, sq: Self::Square, piece: ::Piece); + fn insert(&mut self, sq: ::Square, piece: ::Piece); /// remove clears the given square, and returns the piece that was there. - fn remove(&mut self, sq: Self::Square) -> Option<::Piece>; + fn remove(&mut self, sq: ::Square) -> Option<::Piece>; /// at returns the piece that is in the given square. - fn at(&self, sq: Self::Square) -> Option<::Piece>; + fn at(&self, sq: ::Square) -> Option<::Piece>; // Game Result functions. @@ -118,58 +117,6 @@ where /// color returns the Color part of the given ColoredPiece. fn color(&self) -> Self::Color; } -pub trait Square: RepresentableType -where - Self::File: RepresentableType, - Self::Rank: RepresentableType, -{ - type File; - type Rank; - - fn new(file: Self::File, rank: Self::Rank) -> Self { - Self::unsafe_from(rank.into() * Self::File::N as u8 + file.into()) - } - - fn file(self) -> Self::File { - Self::File::unsafe_from(self.into() % Self::File::N as u8) - } - - fn rank(self) -> Self::Rank { - Self::Rank::unsafe_from(self.into() / Self::File::N as u8) - } - - fn north(self) -> Self { - Self::unsafe_from(self.into() + Self::File::N as u8) - } - - fn south(self) -> Self { - Self::unsafe_from(self.into() - Self::File::N as u8) - } - - fn east(self) -> Self { - Self::unsafe_from(self.into() + 1) - } - - fn west(self) -> Self { - Self::unsafe_from(self.into() - 1) - } -} -pub trait BitBoard {} - -/// 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>: - Copy + Eq + FromStr + Display + From + Into -{ - /// N is the number of specializations of the enum. - const N: usize; - - /// unsafe_from unsafely converts the given number into Self. - fn unsafe_from>(number: T) -> Self { - debug_assert!(number.into() < Self::N); - unsafe { std::mem::transmute_copy(&number) } - } -} /// MoveStore is a trait implemented by types which are able to store moves /// inside themselves and are thus usable in move-generation methods in