Skip to content

Commit

Permalink
fuck this actually compiles hahaha
Browse files Browse the repository at this point in the history
  • Loading branch information
raklaptudirm committed Jul 28, 2024
1 parent 1cd9694 commit 703170a
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 59 deletions.
207 changes: 207 additions & 0 deletions games/src/bitboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use std::fmt::Display;
use std::ops::BitOr;
use std::str::FromStr;

pub trait BitBoard:
Sized
+ Copy
+ From<Self::Square>
+ From<u64>
+ Into<u64>
+ BitOr<Self>
+ From<<Self as BitOr<Self>>::Output>
where
<Self as BitOr<Self>>::Output: Into<Self>,
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() << <Self::Square as Square>::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() >> <Self::Square as Square>::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(<Self::Square as Square>::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(<Self::Square as Square>::File::from(
<Self::Square as Square>::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(<Self as std::convert::Into<u64>>::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(<Self as std::convert::Into<u64>>::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 = <Self as Into<u64>>::into(*self);
*self = <Self as From<u64>>::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(<Self as Into<u64>>::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 <Self::Square as Square>::File.
fn file(file: <Self::Square as Square>::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: <Self::Square as Square>::Rank) -> Self {
Self::from(
Self::FIRST_RANK.into() << (<Self::Square as Square>::File::N * rank.into() as usize),
)
}
}

pub trait Square: RepresentableType<u8>
where
Self::File: RepresentableType<u8>,
Self::Rank: RepresentableType<u8>,
{
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<B: Into<usize>>:
Copy + Eq + FromStr + Display + From<B> + Into<B>
{
/// N is the number of specializations of the enum.
const N: usize;

/// unsafe_from unsafely converts the given number into Self.
fn unsafe_from<T: Copy + Into<usize>>(number: T) -> Self {
debug_assert!(number.into() < Self::N);
unsafe { std::mem::transmute_copy(&number) }
}
}
65 changes: 6 additions & 59 deletions games/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,13 +22,10 @@ where
<Self as Index<Self::ColoredPiece>>::Output: Into<Self::BitBoard>,
<Self as Index<<Self::ColoredPiece as ColoredPiece>::Piece>>::Output: Into<Self::BitBoard>,
<Self as Index<<Self::ColoredPiece as ColoredPiece>::Color>>::Output: Into<Self::BitBoard>,
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;

Expand All @@ -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: <Self::ColoredPiece as ColoredPiece>::Piece);
fn insert(&mut self, sq: <Self::BitBoard as BitBoard>::Square, piece: <Self::ColoredPiece as ColoredPiece>::Piece);
/// remove clears the given square, and returns the piece that was there.
fn remove(&mut self, sq: Self::Square) -> Option<<Self::ColoredPiece as ColoredPiece>::Piece>;
fn remove(&mut self, sq: <Self::BitBoard as BitBoard>::Square) -> Option<<Self::ColoredPiece as ColoredPiece>::Piece>;
/// at returns the piece that is in the given square.
fn at(&self, sq: Self::Square) -> Option<<Self::ColoredPiece as ColoredPiece>::Piece>;
fn at(&self, sq: <Self::BitBoard as BitBoard>::Square) -> Option<<Self::ColoredPiece as ColoredPiece>::Piece>;

// Game Result functions.

Expand Down Expand Up @@ -118,58 +117,6 @@ where
/// color returns the Color part of the given ColoredPiece.
fn color(&self) -> Self::Color;
}
pub trait Square: RepresentableType<u8>
where
Self::File: RepresentableType<u8>,
Self::Rank: RepresentableType<u8>,
{
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<B: Into<usize>>:
Copy + Eq + FromStr + Display + From<B> + Into<B>
{
/// N is the number of specializations of the enum.
const N: usize;

/// unsafe_from unsafely converts the given number into Self.
fn unsafe_from<T: Copy + Into<usize>>(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
Expand Down

0 comments on commit 703170a

Please sign in to comment.