extern crate rand;
use super::sq::SQ;
use super::bit_twiddles::*;
use super::masks::*;
use tools::prng::PRNG;
use super::Player;
use std::mem;
use std::ops::*;
use std::fmt;
use std::hint::unreachable_unchecked;
#[derive(Copy, Clone, Default, Hash, PartialEq, Eq, Debug)]
#[repr(transparent)]
pub struct BitBoard(pub u64);
impl_bit_ops!(BitBoard, u64);
impl BitBoard {
pub const FILE_A: BitBoard = BitBoard(FILE_A);
pub const FILE_B: BitBoard = BitBoard(FILE_B);
pub const FILE_C: BitBoard = BitBoard(FILE_C);
pub const FILE_D: BitBoard = BitBoard(FILE_D);
pub const FILE_E: BitBoard = BitBoard(FILE_E);
pub const FILE_F: BitBoard = BitBoard(FILE_F);
pub const FILE_G: BitBoard = BitBoard(FILE_G);
pub const FILE_H: BitBoard = BitBoard(FILE_H);
pub const RANK_1: BitBoard = BitBoard(RANK_1);
pub const RANK_2: BitBoard = BitBoard(RANK_2);
pub const RANK_3: BitBoard = BitBoard(RANK_3);
pub const RANK_4: BitBoard = BitBoard(RANK_4);
pub const RANK_5: BitBoard = BitBoard(RANK_5);
pub const RANK_6: BitBoard = BitBoard(RANK_6);
pub const RANK_7: BitBoard = BitBoard(RANK_7);
pub const RANK_8: BitBoard = BitBoard(RANK_8);
pub const DARK_SQUARES: BitBoard = BitBoard(DARK_SQUARES);
pub const LIGHT_SQUARES: BitBoard = BitBoard(LIGHT_SQUARES);
pub const ALL: BitBoard = BitBoard(!0);
#[inline(always)]
pub fn to_sq(self) -> SQ {
debug_assert_eq!(self.count_bits(), 1);
SQ(bit_scan_forward(self.0))
}
#[inline(always)]
pub fn count_bits(self) -> u8 {
popcount64(self.0)
}
#[inline(always)]
pub fn bit_scan_forward(self) -> SQ {
SQ(self.bit_scan_forward_u8())
}
#[inline(always)]
pub fn bit_scan_forward_u8(self) -> u8 {
bit_scan_forward(self.0)
}
#[inline(always)]
pub fn more_than_one(self) -> bool {
more_than_one(self.0)
}
#[inline(always)]
pub fn is_empty(self) -> bool {
self.0 == 0
}
#[inline(always)]
pub fn is_not_empty(self) -> bool {
self.0 != 0
}
#[inline(always)]
pub fn lsb(self) -> BitBoard {
BitBoard(self.lsb_u64())
}
#[inline(always)]
pub fn msb(self) -> BitBoard {
BitBoard(msb(self.0))
}
#[inline(always)]
pub fn lsb_u64(self) -> u64 {
lsb(self.0)
}
#[inline(always)]
pub fn pop_lsb(&mut self) -> SQ {
let sq = self.bit_scan_forward();
*self &= *self - 1;
sq
}
#[inline(always)]
pub fn pop_some_lsb(&mut self) -> Option<SQ> {
if self.is_empty() {
None
} else {
Some(self.pop_lsb())
}
}
#[inline(always)]
pub fn pop_lsb_and_bit(&mut self) -> (SQ, BitBoard) {
let sq: SQ = self.bit_scan_forward();
*self &= *self - 1;
(sq, sq.to_bb())
}
#[inline(always)]
pub fn pop_some_lsb_and_bit(&mut self) -> Option<(SQ, BitBoard)> {
if self.is_empty() {
None
} else {
Some(self.pop_lsb_and_bit())
}
}
#[inline]
pub fn frontmost_sq(self, player: Player) -> SQ {
match player {
Player::White => self.msb().to_sq(),
Player::Black => self.bit_scan_forward(),
}
}
#[inline]
pub fn backmost_sq(self, player: Player) -> SQ {
match player {
Player::White => self.bit_scan_forward(),
Player::Black => self.msb().to_sq(),
}
}
#[inline(always)]
pub fn clone_all_occ(bbs: &[[BitBoard; PIECE_TYPE_CNT]; PLAYER_CNT], ) -> [[BitBoard; PIECE_TYPE_CNT]; PLAYER_CNT] {
let new_bbs: [[BitBoard; PIECE_TYPE_CNT]; PLAYER_CNT] = unsafe { mem::transmute_copy(bbs) };
new_bbs
}
#[inline(always)]
pub fn clone_occ_bbs(bbs: &[BitBoard; PLAYER_CNT]) -> [BitBoard; PLAYER_CNT] {
let new_bbs: [BitBoard; PLAYER_CNT] = unsafe { mem::transmute_copy(bbs) };
new_bbs
}
}
impl Shl<SQ> for BitBoard {
type Output = BitBoard;
#[inline(always)]
fn shl(self, rhs: SQ) -> BitBoard {
BitBoard((self.0).wrapping_shl(rhs.0 as u32))
}
}
impl Iterator for BitBoard {
type Item = SQ;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.is_empty() {
None
} else {
Some(self.pop_lsb())
}
}
}
impl fmt::Display for BitBoard {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = &string_u64(reverse_bytes(self.0));
f.pad(s)
}
}
#[derive(Eq, PartialEq)]
enum RandAmount {
VeryDense, Dense, Standard, Sparse, VerySparse, ExtremelySparse, Singular }
pub struct RandBitBoard {
prng: PRNG,
seed: u64,
rand: RandAmount,
max: u16,
min: u16
}
impl Default for RandBitBoard {
fn default() -> Self {
RandBitBoard {
prng: PRNG::init(1),
seed: 0,
rand: RandAmount::Standard,
max: 64,
min: 1
}
}
}
impl RandBitBoard {
pub fn many(mut self, amount: usize) -> Vec<BitBoard> {
let mut boards: Vec<BitBoard> = Vec::with_capacity(amount);
for _x in 0..amount {
boards.push(self.go());
};
boards
}
pub fn one(mut self) -> BitBoard {
self.go()
}
pub fn avg(mut self, bits: u8) -> Self {
self.rand = if bits >= 36 {
RandAmount::VeryDense
} else if bits >= 26 {
RandAmount::Dense
} else if bits >= 12 {
RandAmount::Standard
} else if bits >= 7 {
RandAmount::Sparse
} else if bits >= 5 {
RandAmount::VerySparse
} else {
RandAmount::ExtremelySparse
};
self
}
pub fn allow_empty(mut self) -> Self {
self.min = 0;
self
}
pub fn max(mut self, max: u16) -> Self {
self.max = max;
self
}
pub fn min(mut self, min: u16) -> Self {
self.min = min;
self
}
pub fn pseudo_random(mut self, seed: u64) -> Self {
self.seed = if seed == 0 {1} else {seed};
self.prng = PRNG::init(seed);
self
}
fn go(&mut self) -> BitBoard {
if self.rand == RandAmount::Singular {
return BitBoard(self.prng.singular_bit());
}
loop {
let num = match self.rand {
RandAmount::VeryDense => self.prng.rand() | self.prng.rand(), RandAmount::Dense => self.prng.rand(), RandAmount::Standard => self.prng.rand() & self.prng.rand(), RandAmount::Sparse => self.prng.sparse_rand(), RandAmount::VerySparse => self.prng.sparse_rand() & (self.prng.rand() | self.prng.rand()), RandAmount::ExtremelySparse => self.prng.sparse_rand() & self.prng.rand(), RandAmount::Singular => unsafe {unreachable_unchecked()}
};
let count = popcount64(num) as u16;
if count >= self.min && count <= self.max {
return BitBoard(num);
}
}
}
fn random(&mut self) -> usize {
if self.seed == 0 {
return rand::random::<usize>();
}
self.prng.rand() as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bb_pop_lsb() {
let mut bbs = RandBitBoard::default()
.pseudo_random(2264221)
.min(2)
.avg(5)
.max(15)
.many(100);
while !bbs.is_empty() {
let mut bb = bbs.pop().unwrap();
while bb.is_not_empty() {
let total_pre = bb.count_bits();
let lsb_sq = bb.pop_lsb();
assert!(lsb_sq.is_okay());
assert_eq!(lsb_sq.to_bb() & bb, BitBoard(0));
assert_eq!(bb.count_bits() + 1, total_pre);
}
}
}
#[test]
fn rand_bb_gen_eq() {
let mut bbs_1 = RandBitBoard::default()
.pseudo_random(9010555142588)
.avg(16)
.many(1000);
let mut bbs_2 = RandBitBoard::default()
.pseudo_random(9010555142588)
.avg(16)
.many(1000);
assert_eq!(bbs_1.len(),bbs_2.len());
while !bbs_1.is_empty() {
assert_eq!(bbs_1.pop(), bbs_2.pop());
}
}
}