use std::{fmt, ops};
use itertools::Itertools;
use crate::bitboard::iterator::BitBoardIterator;
use crate::square::Square::H1;
use crate::{Dir, Square};
use std::iter::FromIterator;
pub mod constants;
mod cords;
mod iterator;
#[derive(Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
pub struct BitBoard(pub u64);
impl BitBoard {
pub fn contains(self, square: Square) -> bool {
self.0 & (1u64 << (square as u64)) != 0
}
pub fn subsumes(self, other: BitBoard) -> bool {
(other - self).is_empty()
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn is_populated(self) -> bool {
self.0 != 0
}
pub fn intersects(self, other: BitBoard) -> bool {
!(self & other).is_empty()
}
pub fn size(self) -> usize {
self.0.count_ones() as usize
}
pub fn iter(self) -> impl Iterator<Item = Square> {
self.into_iter()
}
pub fn first(self) -> Option<Square> {
self.into_iter().next()
}
pub fn least_set_bit(self) -> BitBoard {
let trailing = self.0.trailing_zeros();
if trailing == 64 {
BitBoard::EMPTY
} else {
BitBoard(1u64 << trailing)
}
}
pub fn cord(source: Square, target: Square) -> BitBoard {
cords::get_cord(source, target)
}
pub const EMPTY: BitBoard = BitBoard(0u64);
pub const ALL: BitBoard = BitBoard(!0u64);
pub const RANKS: [BitBoard; 8] = [
BitBoard(255),
BitBoard(65280),
BitBoard(16711680),
BitBoard(4278190080),
BitBoard(1095216660480),
BitBoard(280375465082880),
BitBoard(71776119061217280),
BitBoard(18374686479671623680),
];
pub const FILES: [BitBoard; 8] = [
BitBoard(72340172838076673),
BitBoard(144680345676153346),
BitBoard(289360691352306692),
BitBoard(578721382704613384),
BitBoard(1157442765409226768),
BitBoard(2314885530818453536),
BitBoard(4629771061636907072),
BitBoard(9259542123273814144),
];
}
impl IntoIterator for BitBoard {
type Item = Square;
type IntoIter = BitBoardIterator;
fn into_iter(self) -> Self::IntoIter {
BitBoardIterator(self.0)
}
}
impl FromIterator<Square> for BitBoard {
fn from_iter<I: IntoIterator<Item = Square>>(iter: I) -> Self {
iter.into_iter().fold(BitBoard::EMPTY, |a, b| a | b)
}
}
impl FromIterator<BitBoard> for BitBoard {
fn from_iter<I: IntoIterator<Item = BitBoard>>(iter: I) -> Self {
iter.into_iter().fold(BitBoard::EMPTY, |a, b| a | b)
}
}
impl ops::Shr<u8> for BitBoard {
type Output = Self;
fn shr(self, shift: u8) -> Self {
BitBoard(self.0 >> shift as u64)
}
}
impl ops::Shl<u8> for BitBoard {
type Output = Self;
fn shl(self, shift: u8) -> Self {
BitBoard(self.0 << shift as u64)
}
}
impl ops::Not for BitBoard {
type Output = Self;
fn not(self) -> Self {
BitBoard(!self.0)
}
}
impl ops::Sub<BitBoard> for BitBoard {
type Output = Self;
fn sub(self, other: BitBoard) -> Self {
BitBoard(self.0 & !other.0)
}
}
impl ops::Sub<Square> for BitBoard {
type Output = Self;
fn sub(self, other: Square) -> Self {
BitBoard(self.0 & !loc(other))
}
}
impl ops::BitXor<BitBoard> for BitBoard {
type Output = Self;
fn bitxor(self, other: BitBoard) -> Self {
BitBoard(self.0 ^ other.0)
}
}
impl ops::BitXor<Square> for BitBoard {
type Output = Self;
fn bitxor(self, rhs: Square) -> Self {
BitBoard(self.0 ^ loc(rhs))
}
}
impl ops::BitOr<BitBoard> for BitBoard {
type Output = Self;
fn bitor(self, other: BitBoard) -> Self {
BitBoard(self.0 | other.0)
}
}
impl ops::BitOr<Square> for BitBoard {
type Output = Self;
fn bitor(self, other: Square) -> Self {
BitBoard(self.0 | loc(other))
}
}
impl ops::BitAnd<BitBoard> for BitBoard {
type Output = Self;
fn bitand(self, other: BitBoard) -> Self {
BitBoard(self.0 & other.0)
}
}
impl ops::BitAnd<Square> for BitBoard {
type Output = Self;
fn bitand(self, other: Square) -> Self {
BitBoard(self.0 & loc(other))
}
}
impl ops::BitXorAssign<BitBoard> for BitBoard {
fn bitxor_assign(&mut self, rhs: BitBoard) {
self.0 = self.0 ^ rhs.0;
}
}
impl ops::BitXorAssign<Square> for BitBoard {
fn bitxor_assign(&mut self, rhs: Square) {
self.0 = self.0 ^ (1u64 << (rhs as u64));
}
}
impl ops::BitOrAssign<BitBoard> for BitBoard {
fn bitor_assign(&mut self, rhs: BitBoard) {
self.0 = self.0 | rhs.0;
}
}
impl ops::BitOrAssign<Square> for BitBoard {
fn bitor_assign(&mut self, rhs: Square) {
self.0 = self.0 | (1u64 << (rhs as u64));
}
}
impl fmt::Debug for BitBoard {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{{}}}", self.into_iter().join(", "))
}
}
impl fmt::Display for BitBoard {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{{}}}", self.into_iter().join(", "))
}
}
fn loc(sq: Square) -> u64 {
1u64 << (sq as u64)
}
#[allow(dead_code)]
fn create_files() -> Vec<BitBoard> {
(H1.search(Dir::W) | H1)
.into_iter()
.map(|sq| sq.search(Dir::N) | sq)
.collect()
}
#[allow(dead_code)]
fn create_ranks() -> Vec<BitBoard> {
(H1.search(Dir::N) | H1)
.into_iter()
.map(|sq| sq.search(Dir::W) | sq)
.collect()
}
#[cfg(test)]
mod test {
use crate::bitboard::BitBoard;
use crate::square::Square::*;
use super::*;
#[test]
fn test_from_square_iter() {
assert_eq!(F1 | G6, vec!(F1, G6).into_iter().collect());
}
#[test]
fn test_into_iter() {
assert_eq!(vec![F1, G6], (F1 | G6).into_iter().collect::<Vec<Square>>());
}
#[test]
fn test_display() {
let result = A1 | H7 | D5;
assert_eq!("{a1, d5, h7}".to_owned(), format!("{}", result));
}
#[test]
fn test_size() {
assert_eq!(0, BitBoard::EMPTY.size());
assert_eq!(64, BitBoard::ALL.size());
assert_eq!(3, (A3 | G6 | H4).size());
}
#[test]
fn test_create_files() {
assert_eq!(H1 | H2 | H3 | H4 | H5 | H6 | H7 | H8, create_files()[0]);
}
#[test]
fn test_create_ranks() {
assert_eq!(A3 | B3 | C3 | D3 | E3 | F3 | G3 | H3, create_ranks()[2]);
}
#[test]
fn test_lsb() {
assert_eq!(BitBoard::EMPTY, BitBoard::EMPTY.least_set_bit());
assert_eq!(G1.lift(), (E4 | G1).least_set_bit());
assert_eq!(E3.lift(), (E3 | G5).least_set_bit());
assert_eq!(A8.lift(), A8.lift().least_set_bit());
}
}