board_game/games/go/
hash.rs1use std::fmt::{Debug, Formatter};
2use std::hash::{Hash, Hasher};
3
4use lazy_static::lazy_static;
5use rand::distributions::{Distribution, Standard};
6use rand::Rng;
7
8use crate::board::Player;
9use crate::games::go::{FlatTile, State, GO_MAX_AREA};
10use crate::util::tiny::consistent_rng;
11
12type Inner = u128;
13
14#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
15pub struct Zobrist(Inner);
16
17pub struct HashData {
18 color_tile: [Vec<Zobrist>; 2],
19 color_turn: [Zobrist; 2],
20 pass_state: [Zobrist; 3],
21}
22
23impl Zobrist {
24 pub fn for_color_tile(color: Player, tile: FlatTile) -> Zobrist {
25 HASH_DATA.color_tile[color.index() as usize][tile.index() as usize]
26 }
27
28 pub fn for_color_turn(color: Player) -> Zobrist {
29 HASH_DATA.color_turn[color.index() as usize]
30 }
31
32 pub fn for_pass_state(state: State) -> Zobrist {
33 let state_index = match state {
35 State::Normal => 0,
36 State::Passed => 1,
37 State::Done(_) => 2,
38 };
39 HASH_DATA.pass_state[state_index]
40 }
41}
42
43lazy_static! {
45 static ref HASH_DATA: HashData = HashData::new();
46}
47
48impl HashData {
49 #[allow(clippy::new_without_default)]
50 #[inline(never)]
51 pub fn new() -> HashData {
52 let mut rng = consistent_rng();
53 let vec_len = GO_MAX_AREA as usize;
54 HashData {
55 color_tile: [gen_vec(vec_len, &mut rng), gen_vec(vec_len, &mut rng)],
56 color_turn: gen_array(&mut rng),
57 pass_state: gen_array(&mut rng),
58 }
59 }
60}
61
62impl Debug for HashData {
63 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("HashData").finish_non_exhaustive()
65 }
66}
67
68impl Distribution<Zobrist> for Standard {
69 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Zobrist {
70 Zobrist(rng.gen())
71 }
72}
73
74fn gen_array<const N: usize>(rng: &mut impl Rng) -> [Zobrist; N] {
75 let mut array = [Zobrist::default(); N];
76 for x in &mut array {
77 *x = rng.gen();
78 }
79 array
80}
81
82fn gen_vec(len: usize, rng: &mut impl Rng) -> Vec<Zobrist> {
83 Standard.sample_iter(rng).take(len).collect()
84}
85
86impl Debug for Zobrist {
87 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88 write!(
90 f,
91 "Zobrist({:#0width$x})",
92 self.0,
93 width = (Inner::BITS / 8 + 2) as usize
94 )
95 }
96}
97
98impl std::ops::BitXor for Zobrist {
99 type Output = Self;
100
101 fn bitxor(self, rhs: Self) -> Self::Output {
102 Zobrist(self.0 ^ rhs.0)
103 }
104}
105
106impl std::ops::BitXorAssign for Zobrist {
107 fn bitxor_assign(&mut self, rhs: Self) {
108 self.0 ^= rhs.0;
109 }
110}
111
112impl nohash_hasher::IsEnabled for Zobrist {}
113
114impl Hash for Zobrist {
115 fn hash<H: Hasher>(&self, state: &mut H) {
116 state.write_u64((self.0 as u64) ^ ((self.0 >> 64) as u64));
117 }
118}