use std::{fmt, hash, mem, ptr};
use core::castle::Rights;
use core::misc::Extract;
use core::piece::Role;
use core::square::{File, Square};
mod tables;
const NUM_PIECES: usize = 6;
const NUM_SQUARES: usize = 64;
const PIECE_TOTAL: usize = NUM_SQUARES * NUM_PIECES;
const NUM_CASTLE: usize = 0b1111 + 1;
const NUM_COLORS: usize = 1;
const NUM_EP: usize = 8;
const NUM_KEYS: usize = PIECE_TOTAL + NUM_CASTLE + NUM_EP + NUM_COLORS;
const NUM_BYTES: usize = NUM_KEYS * 8;
type Keys = [u64; NUM_KEYS];
type Bytes = [u8; NUM_BYTES];
pub static KEYS: Zobrist = tables::STATIC;
#[repr(C)]
pub struct Zobrist {
pub pieces: [[u64; NUM_SQUARES]; NUM_PIECES],
pub castle: [u64; NUM_CASTLE],
pub en_passant: [u64; NUM_EP],
pub color: u64,
}
impl Clone for Zobrist {
#[inline]
fn clone(&self) -> Zobrist {
unsafe { ptr::read(self) }
}
}
impl fmt::Debug for Zobrist {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let pieces: [&[u64]; 6] = [
&self.pieces[0], &self.pieces[1], &self.pieces[2],
&self.pieces[3], &self.pieces[4], &self.pieces[5],
];
f.debug_struct("Zobrist")
.field("pieces", &pieces)
.field("castle", &self.castle)
.field("en_passant", &self.en_passant)
.field("color", &self.color)
.finish()
}
}
impl hash::Hash for Zobrist {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
state.write(self.as_bytes());
}
}
impl Default for Zobrist {
#[inline]
fn default() -> Zobrist {
unsafe { mem::zeroed() }
}
}
impl PartialEq for Zobrist {
#[inline]
fn eq(&self, other: &Zobrist) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for Zobrist {}
impl AsRef<[u64]> for Zobrist {
#[inline]
fn as_ref(&self) -> &[u64] { self.as_slice() }
}
impl AsMut<[u64]> for Zobrist {
#[inline]
fn as_mut(&mut self) -> &mut [u64] { self.as_mut_slice() }
}
impl AsRef<[u8]> for Zobrist {
#[inline]
fn as_ref(&self) -> &[u8] { self.as_bytes() }
}
impl AsMut<[u8]> for Zobrist {
#[inline]
fn as_mut(&mut self) -> &mut [u8] { self.as_bytes_mut() }
}
#[cfg(any(test, feature = "rand"))]
impl ::rand::Rand for Zobrist {
fn rand<R: ::rand::Rng>(rng: &mut R) -> Zobrist {
let mut zobrist = Zobrist::default();
rng.fill_bytes(zobrist.as_bytes_mut());
zobrist
}
}
impl Zobrist {
#[inline]
pub fn piece(&self, role: Role, square: Square) -> u64 {
self.pieces[role as usize][square as usize]
}
#[inline]
pub fn castle(&self, rights: Rights) -> u64 {
*rights.extract(&self.castle)
}
#[inline]
pub fn en_passant(&self, file: File) -> u64 {
self.en_passant[file as usize]
}
#[inline]
pub fn clear(&mut self) {
unsafe { ::util::zero(self) }
}
#[inline]
pub fn as_slice(&self) -> &[u64] {
let ptr = self as *const Zobrist as *const Keys;
unsafe { &*ptr }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u64] {
let ptr = self as *mut Zobrist as *mut Keys;
unsafe { &mut *ptr }
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
let ptr = self as *const Zobrist as *const Bytes;
unsafe { &*ptr }
}
#[inline]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
let ptr = self as *mut Zobrist as *mut Bytes;
unsafe { &mut *ptr }
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{Rng, SeedableRng, ChaChaRng};
assert_eq_size!(type_size; Zobrist, Keys, Bytes);
#[test]
fn keys_init() {
const SEED: u32 = 0xDEAD_BEEF;
let mut rng = ChaChaRng::from_seed(&[SEED]);
let zobrist = rng.gen::<Zobrist>();
assert_eq!(zobrist, KEYS);
}
}