Skip to content

Commit

Permalink
Create ZobristHashable trait.
Browse files Browse the repository at this point in the history
To select which variants can use the `Zobrist` trait, solve issues raised in niklasf#45.

Exposed so third-party variants can implement it.

* `Atomic` cannot use it because `play_unchecked` does not handle explosions.
* `CrazyHouse` is not properly supported because it does not account for the `Pocket` of the player.
* `TreeCheck` is not properly supported because it does not account for the `Check` in the position.
  • Loading branch information
kraktus committed Aug 31, 2021
1 parent 69c8de8 commit 8a35902
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,4 @@ pub use crate::setup::{Castles, Setup};
pub use crate::movelist::MoveList;
pub use crate::position::{Chess, Outcome, Position, FromSetup, PlayError, PositionError, PositionErrorKinds};
pub use crate::perft::perft;
pub use crate::zobrist::{Zobrist, zobrist_from_pos};
pub use crate::zobrist::{Zobrist, ZobristHashable, zobrist_from_pos};
11 changes: 11 additions & 0 deletions src/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::types::{CastlingSide, CastlingMode, Move, Piece, Role, RemainingCheck
use crate::material::Material;
use crate::setup::{Castles, EpSquare, Setup, SwapTurn};
use crate::movelist::MoveList;
use crate::zobrist::ZobristHashable;

/// Outcome of a game.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
Expand Down Expand Up @@ -671,6 +672,8 @@ impl Position for Chess {
fn variant_outcome(&self) -> Option<Outcome> { None }
}

impl ZobristHashable for Chess {}

#[cfg(feature = "variant")]
pub(crate) mod variant {
use super::*;
Expand Down Expand Up @@ -1022,6 +1025,8 @@ pub(crate) mod variant {
}
}

impl ZobristHashable for Antichess {}

/// A King of the Hill position.
#[derive(Clone, Debug, Default)]
pub struct KingOfTheHill {
Expand Down Expand Up @@ -1109,6 +1114,8 @@ pub(crate) mod variant {
}
}

impl ZobristHashable for KingOfTheHill {}

/// A Three-Check position.
#[derive(Clone, Debug, Default)]
pub struct ThreeCheck {
Expand Down Expand Up @@ -1532,6 +1539,8 @@ pub(crate) mod variant {
}
}

impl ZobristHashable for RacingKings {}

/// A Horde position.
#[derive(Clone, Debug)]
pub struct Horde {
Expand Down Expand Up @@ -1931,6 +1940,8 @@ pub(crate) mod variant {
}
}

impl ZobristHashable for Horde {}

fn add_king_promotions(moves: &mut MoveList) {
let mut king_promotions = MoveList::new();

Expand Down
25 changes: 16 additions & 9 deletions src/zobrist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@ use std::num::NonZeroU32;

include!(concat!(env!("OUT_DIR"), "/zobrist.rs")); // generated by build.rs

/// Used to discriminate which variants support Zobrist hashing.
pub trait ZobristHashable {}

pub trait PositionHashable: Position + ZobristHashable {} // trait alias

#[derive(Debug)]
pub struct Zobrist<P> {
pos: P,
pub struct Zobrist<P: PositionHashable> {
pos: PositionHashable,
zobrist: u64
}

impl <P:Position> Zobrist<P> {
impl <P:PositionHashable> ZobristHashable for Zobrist<P> {}

impl <P:PositionHashable> Zobrist<P> {
/// Computes the zobrist hash of the current game state
pub fn hash(&self) -> u64 {
self.zobrist
}
}

impl <P:Default + Position> Default for Zobrist<P> {
impl <P:Default + PositionHashable> Default for Zobrist<P> {
fn default() -> Self {
let pos = P::default();
let board = pos.board();
Expand All @@ -35,7 +42,7 @@ impl <P:Default + Position> Default for Zobrist<P> {
}
}

impl <P:FromSetup + Position> FromSetup for Zobrist<P> {
impl <P:FromSetup + PositionHashable> FromSetup for Zobrist<P> {
fn from_setup(setup: &dyn Setup, mode: CastlingMode) -> Result<Self, PositionError<Self>> {
// create the underlying from the setup
let pos = match P::from_setup(setup, mode) {
Expand All @@ -48,7 +55,7 @@ impl <P:FromSetup + Position> FromSetup for Zobrist<P> {
}

// Simply call through to the underlying methods
impl <P: Position> Setup for Zobrist<P> {
impl <P: PositionHashable> Setup for Zobrist<P> {
#[inline(always)]
fn board(&self) -> &Board {
self.pos.board()
Expand Down Expand Up @@ -91,7 +98,7 @@ impl <P: Position> Setup for Zobrist<P> {
}

// call through to the underlying methods for everything except `play_unchecked`
impl <P: Position> Position for Zobrist<P> {
impl <P: PositionHashable> Position for Zobrist<P> {
#[inline(always)]
fn legal_moves(&self) -> MoveList {
self.pos.legal_moves()
Expand Down Expand Up @@ -215,7 +222,7 @@ fn zobrist_from_board(board: &Board) -> u64 {
}

/// Computes the Zobrist hash given a position.
pub fn zobrist_from_pos<T: Position>(pos: &T) -> u64 {
pub fn zobrist_from_pos<T: PositionHashable>(pos: &T) -> u64 {
// compute the zobrist hash from the pieces on the board
let mut zobrist = zobrist_from_board(&pos.board());

Expand Down Expand Up @@ -266,7 +273,7 @@ fn castle(color :Color, castle: CastlingSide) -> u64 {

#[cfg(test)]
mod zobrist_tests {
use crate::{Square, Piece, Chess, Position, CastlingMode, Move};
use crate::{Square, Piece, Chess, PositionHashable, CastlingMode, Move};
use crate::fen::{epd, Fen};
use crate::zobrist::{square, Zobrist};
use std::collections::{HashSet, HashMap};
Expand Down

0 comments on commit 8a35902

Please sign in to comment.