pub mod types {
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct CastlingRight(pub u32);
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Key(pub u64);
impl std::ops::BitXor<Key> for Key {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self {
Key(self.0 ^ rhs.0)
}
}
impl std::ops::BitXorAssign<Key> for Key {
fn bitxor_assign(&mut self, rhs: Key) {
*self = *self ^ rhs;
}
}
impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "{:X}", self.0)
}
}
impl std::ops::BitAnd<CastlingRight> for CastlingRight {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
CastlingRight(self.0 & rhs.0)
}
}
impl std::ops::BitOr<CastlingRight> for CastlingRight {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
CastlingRight(self.0 | rhs.0)
}
}
impl std::ops::BitAndAssign<CastlingRight> for CastlingRight {
fn bitand_assign(&mut self, rhs: Self) {
*self = *self & rhs;
}
}
impl std::ops::BitOrAssign<CastlingRight> for CastlingRight {
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
impl std::ops::Not for CastlingRight {
type Output = CastlingRight;
fn not(self) -> Self {
CastlingRight(!self.0)
}
}
impl std::cmp::PartialEq<u32> for CastlingRight {
fn eq(&self, rhs: &u32) -> bool {
debug_assert!(*rhs == 0);
self.0 == *rhs
}
}
}
pub mod misc {
#[derive(Clone, Copy)]
pub struct Prng(u64);
impl Prng {
pub fn new(seed: u64) -> Prng {
Prng(seed)
}
pub fn rand64(&mut self) -> u64 {
self.0 ^= self.0 >> 12;
self.0 ^= self.0 << 25;
self.0 ^= self.0 >> 27;
u64::wrapping_mul(self.0, 2685821657736338717)
}
}
}
pub mod zobrist {
use crate::stockfish::{misc, types::*};
static mut PSQ: [[Key; 64]; 16] = [[Key(0); 64]; 16];
static mut ENPASSANT: [Key; 8] = [Key(0); 8];
static mut CASTLING: [Key; 16] = [Key(0); 16];
static mut SIDE: Key = Key(0);
pub fn psq(pc: u32, s: u32) -> Key {
assert!(pc < 16, "piece index out of bounds");
assert!(s < 64, "square index out of bounds");
unsafe { PSQ[pc as usize][s as usize] }
}
pub fn enpassant(f: u32) -> Key {
assert!(f < 8, "en-passant index out of bounds");
unsafe { ENPASSANT[f as usize] }
}
pub fn castling(cr: u32) -> Key {
assert!(cr < 16, "castling right index out of bounds");
unsafe { CASTLING[cr as usize] }
}
pub fn side() -> Key {
unsafe { SIDE }
}
pub fn init() {
let mut rng = misc::Prng::new(1070372);
#[allow(static_mut_refs)]
unsafe {
#[allow(clippy::needless_range_loop)]
for i in 1..15 {
if i != 7 && i != 8 {
for s in 0..64 {
PSQ[i][s] = Key(rng.rand64());
}
}
}
for item in &mut ENPASSANT {
*item = Key(rng.rand64());
}
for item in &mut CASTLING {
*item ^= Key(rng.rand64());
}
SIDE = Key(rng.rand64());
}
}
}
use shakmaty::{Castles, CastlingSide, Color, EnPassantMode, Piece, Position, Role};
use types::*;
pub fn stockfish_hash(position: &dyn Position) -> u64 {
let mut hash = Key(0);
let board = position.board();
for role in Role::ALL {
for color in [Color::Black, Color::White] {
let piece = role.of(color);
let index = stockfish_piece(&piece);
for square in board.by_piece(piece) {
hash ^= zobrist::psq(index, square as u32);
}
}
}
if let Some(ep_square) = position.ep_square(EnPassantMode::Legal) {
hash ^= zobrist::enpassant(ep_square.file() as u32)
}
if position.turn() == Color::Black {
hash ^= zobrist::side();
}
let castles = position.castles();
if !castles.is_empty() {
hash ^= zobrist::castling(stockfish_castling_right(castles));
}
hash.0
}
#[inline(always)]
fn stockfish_piece(piece: &Piece) -> u32 {
match piece {
Piece {
color: Color::White,
role: Role::Pawn,
} => 1,
Piece {
color: Color::White,
role: Role::Knight,
} => 2,
Piece {
color: Color::White,
role: Role::Bishop,
} => 3,
Piece {
color: Color::White,
role: Role::Rook,
} => 4,
Piece {
color: Color::White,
role: Role::Queen,
} => 5,
Piece {
color: Color::White,
role: Role::King,
} => 6,
Piece {
color: Color::Black,
role: Role::Pawn,
} => 9,
Piece {
color: Color::Black,
role: Role::Knight,
} => 10,
Piece {
color: Color::Black,
role: Role::Bishop,
} => 11,
Piece {
color: Color::Black,
role: Role::Rook,
} => 12,
Piece {
color: Color::Black,
role: Role::Queen,
} => 13,
Piece {
color: Color::Black,
role: Role::King,
} => 14,
}
}
#[inline(always)]
fn stockfish_castling_right(castles: &Castles) -> u32 {
let mut castling_right: CastlingRight = CastlingRight(0);
if castles.has(Color::White, CastlingSide::KingSide) {
castling_right |= CastlingRight(1);
}
if castles.has(Color::White, CastlingSide::QueenSide) {
castling_right |= CastlingRight(2);
}
if castles.has(Color::Black, CastlingSide::KingSide) {
castling_right |= CastlingRight(4);
}
if castles.has(Color::Black, CastlingSide::QueenSide) {
castling_right |= CastlingRight(8);
}
castling_right.0
}