use core::{hash, ops, mem};
#[cfg(feature = "simd")]
use core::simd::u8x64;
use board::{Bitboard, PieceMap};
use castle::Right;
use color::Color;
use piece::{Piece, Role};
use square::Square;
use uncon::*;
#[cfg(all(test, nightly))]
mod benches;
#[cfg(test)]
mod tests;
mod values {
use super::*;
const PAWN: u64 = 0x00FF00000000FF00;
const KNIGHT: u64 = squares!(B1, B8, G1, G8);
const BISHOP: u64 = squares!(C1, C8, F1, F8);
const ROOK: u64 = squares!(A1, A8, H1, H8);
const QUEEN: u64 = squares!(D1, D8);
const KING: u64 = squares!(E1, E8);
const WHITE: u64 = 0x000000000000FFFF;
const BLACK: u64 = 0xFFFF000000000000;
pub const STANDARD: MultiBoard = MultiBoard {
pieces: [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING],
colors: [WHITE, BLACK],
};
}
const NUM_PIECES: usize = 6;
const NUM_COLORS: usize = 2;
const NUM_BOARDS: usize = NUM_PIECES + NUM_COLORS;
const NUM_BYTES: usize = NUM_BOARDS * 8;
#[repr(C)]
#[derive(Clone, Eq)]
pub struct MultiBoard {
pieces: [u64; NUM_PIECES],
colors: [u64; NUM_COLORS],
}
impl PartialEq for MultiBoard {
#[inline]
fn eq(&self, other: &Self) -> bool {
#[cfg(feature = "simd")]
{
self as *const _ == other as *const _ || self.simd() == other.simd()
}
#[cfg(not(feature = "simd"))]
{
self.bytes()[..] == other.bytes()[..]
}
}
}
impl Default for MultiBoard {
#[inline]
fn default() -> MultiBoard {
unsafe { mem::zeroed() }
}
}
impl AsRef<[u64]> for MultiBoard {
#[inline]
fn as_ref(&self) -> &[u64] {
let array = self as *const _ as *const [_; NUM_BOARDS];
unsafe { &*array }
}
}
impl AsMut<[u64]> for MultiBoard {
#[inline]
fn as_mut(&mut self) -> &mut [u64] {
let array = self as *mut _ as *mut [_; NUM_BOARDS];
unsafe { &mut *array }
}
}
impl AsRef<[Bitboard]> for MultiBoard {
#[inline]
fn as_ref(&self) -> &[Bitboard] {
let array = self as *const _ as *const [_; NUM_BOARDS];
unsafe { &*array }
}
}
impl AsMut<[Bitboard]> for MultiBoard {
#[inline]
fn as_mut(&mut self) -> &mut [Bitboard] {
let array = self as *mut _ as *mut [_; NUM_BOARDS];
unsafe { &mut *array }
}
}
impl<'a> From<&'a PieceMap> for MultiBoard {
fn from(map: &PieceMap) -> MultiBoard {
let mut board = MultiBoard::default();
for (square, &piece) in map {
board.insert_unchecked(square, piece);
}
board
}
}
impl hash::Hash for MultiBoard {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
state.write(self.bytes());
}
}
impl ops::Index<Role> for MultiBoard {
type Output = Bitboard;
#[inline]
fn index(&self, role: Role) -> &Bitboard {
Bitboard::convert_ref(&self.pieces[role as usize])
}
}
impl ops::IndexMut<Role> for MultiBoard {
#[inline]
fn index_mut(&mut self, role: Role) -> &mut Bitboard {
Bitboard::convert_mut(&mut self.pieces[role as usize])
}
}
impl ops::Index<Color> for MultiBoard {
type Output = Bitboard;
#[inline]
fn index(&self, color: Color) -> &Bitboard {
Bitboard::convert_ref(&self.colors[color as usize])
}
}
impl ops::IndexMut<Color> for MultiBoard {
#[inline]
fn index_mut(&mut self, color: Color) -> &mut Bitboard {
Bitboard::convert_mut(&mut self.colors[color as usize])
}
}
impl MultiBoard {
pub const STANDARD: MultiBoard = values::STANDARD;
#[cfg(feature = "simd")]
#[inline]
fn simd(&self) -> u8x64 {
u8x64::load_unaligned(self.bytes())
}
#[inline]
fn bytes(&self) -> &[u8; NUM_BYTES] {
unsafe { self.into_unchecked() }
}
#[inline]
pub fn clear(&mut self) {
unsafe { ::util::zero(self) }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.all_bits().is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.all_bits().len()
}
#[inline]
pub fn all_bits(&self) -> Bitboard {
Bitboard(self.colors[0] | self.colors[1])
}
#[inline]
pub fn bitboard<T: Index>(&self, value: T) -> Bitboard {
value.bitboard(self)
}
#[inline]
pub fn royals(&self) -> Bitboard {
self.bitboard(Role::Queen) | self.bitboard(Role::King)
}
#[inline]
pub fn first<T: Index>(&self, value: T) -> Option<Square> {
self.bitboard(value).lsb()
}
#[inline]
pub unsafe fn first_unchecked<T: Index>(&self, value: T) -> Square {
self.bitboard(value).lsb_unchecked()
}
#[inline]
pub fn last<T: Index>(&self, value: T) -> Option<Square> {
self.bitboard(value).msb()
}
#[inline]
pub unsafe fn last_unchecked<T: Index>(&self, value: T) -> Square {
self.bitboard(value).msb_unchecked()
}
#[inline]
pub fn count<T: Index>(&self, value: T) -> usize {
self.bitboard(value).len()
}
#[inline]
pub fn contains<T, U>(&self, bits: T, value: U) -> bool
where T: Into<Bitboard>, U: Index
{
self.bitboard(value).contains(bits)
}
#[inline]
pub fn contains_any<T, U>(&self, bits: T, value: U) -> bool
where T: Into<Bitboard>, U: Index
{
!(self.bitboard(value) & bits).is_empty()
}
#[inline]
pub fn insert<T: Into<Bitboard>>(&mut self, bits: T, piece: Piece) {
let value = bits.into();
self.remove_all(value);
self.insert_unchecked(value, piece);
}
#[inline]
pub fn insert_unchecked<T: Into<Bitboard>>(&mut self, bits: T, piece: Piece) {
let value = bits.into();
self[piece.color()] |= value;
self[piece.role() ] |= value;
}
#[inline]
pub fn remove<T, U>(&mut self, bits: T, value: U)
where T: Into<Bitboard>, U: Index
{
value.remove(bits, self);
}
#[inline]
pub fn remove_unchecked<T, U>(&mut self, bits: T, value: U)
where T: Into<Bitboard>, U: Index
{
value.remove_unchecked(bits, self);
}
#[inline]
pub fn remove_all<T: Into<Bitboard>>(&mut self, bits: T) {
let value = !bits.into().0;
for board in AsMut::<[u64]>::as_mut(self) {
*board &= value;
}
}
#[inline]
pub fn split(&self) -> (&[Bitboard; NUM_COLORS], &[Bitboard; NUM_PIECES]) {
let colors = &self.colors as *const _ as *const _;
let pieces = &self.pieces as *const _ as *const _;
unsafe { (&*colors, &*pieces) }
}
#[inline]
pub fn split_mut(&mut self) -> (&mut [Bitboard; NUM_COLORS], &mut [Bitboard; NUM_PIECES]) {
let colors = &mut self.colors as *mut _ as *mut _;
let pieces = &mut self.pieces as *mut _ as *mut _;
unsafe { (&mut *colors, &mut *pieces) }
}
pub fn is_attacked(&self, sq: Square, player: Color) -> bool {
macro_rules! check {
($e:expr) => { if $e { return true } };
}
let opp = self.bitboard(!player);
let all = opp | self.bitboard(player);
let pawns = opp & self.bitboard(Role::Pawn);
check!(pawns.intersects(sq.pawn_attacks(player)));
let knights = opp & self.bitboard(Role::Knight);
check!(knights.intersects(sq.knight_attacks()));
let kings = opp & (self.bitboard(Role::King));
check!(kings.intersects(sq.king_attacks()));
let queens = self.bitboard(Role::Queen);
let bishops = opp & (self.bitboard(Role::Bishop) | queens);
check!(bishops.intersects(sq.bishop_attacks(all)));
let rooks = opp & (self.bitboard(Role::Rook) | queens);
rooks.intersects(sq.rook_attacks(all))
}
#[inline]
pub fn castle(&mut self, right: Right) {
static MASKS: [(u64, u64); 4] = [
(squares!(E1, G1), squares!(H1, F1)),
(squares!(E1, C1), squares!(A1, D1)),
(squares!(E8, G8), squares!(H8, F8)),
(squares!(E8, C8), squares!(A8, D8)),
];
let (king, rook) = MASKS[right as usize];
self[right.color()] ^= king | rook;
self[Role::King] ^= king;
self[Role::Rook] ^= rook;
}
}
pub trait Index {
fn bitboard(self, board: &MultiBoard) -> Bitboard;
fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard);
fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard);
}
impl Index for Color {
#[inline]
fn bitboard(self, board: &MultiBoard) -> Bitboard {
board[self]
}
#[inline]
fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
self.remove_unchecked(board[self] & bits.into(), board);
}
#[inline]
fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
let value = !bits.into().0;
board[self] &= value;
for piece in &mut board.pieces {
*piece &= value;
}
}
}
impl Index for Piece {
#[inline]
fn bitboard(self, board: &MultiBoard) -> Bitboard {
self.color().bitboard(board) & self.role().bitboard(board)
}
#[inline]
fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
let value = board[self.color()] | board[self.role()];
self.remove_unchecked(value & bits.into(), board);
}
#[inline]
fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
let value = !bits.into().0;
board[self.color()] &= value;
board[self.role() ] &= value;
}
}
impl Index for Role {
#[inline]
fn bitboard(self, board: &MultiBoard) -> Bitboard {
board[self]
}
#[inline]
fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
self.remove_unchecked(board[self] & bits.into(), board);
}
#[inline]
fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
let value = !bits.into().0;
board[self] &= value;
for color in &mut board.colors {
*color &= value;
}
}
}