competitive_library/other/
zobrist_hash.rs1use super::xorshift::XorShift;
3use std::collections::HashSet;
4
5#[derive(Clone, Default)]
6pub struct ZobristHash<T: Eq + std::hash::Hash + Copy> {
7 map: std::collections::HashMap<T, u64>,
8 rand: XorShift<u64>,
9}
10
11impl<T: Eq + std::hash::Hash + Copy> ZobristHash<T> {
12 pub fn new() -> Self {
13 Self {
14 map: std::collections::HashMap::<T, u64>::new(),
15 rand: XorShift::<u64>::new(),
16 }
17 }
18 #[allow(clippy::or_fun_call)]
19 pub fn hash(&mut self, hash: u64, add: T) -> u64 {
20 hash ^ *self.map.entry(add).or_insert(self.rand.next().unwrap())
21 }
22 pub fn hash_vec_from_vec(&mut self, v: &[T]) -> Vec<u64> {
23 let mut set = std::collections::HashSet::new();
24 let mut ret = vec![];
25
26 let mut hash = 0;
27 for &value in v.iter() {
28 if !set.contains(&value) {
29 set.insert(value);
30 hash = self.hash(hash, value);
31 }
32 ret.push(hash);
33 }
34 ret
35 }
36 pub fn hash_from_set(&mut self, set: &HashSet<T>) -> u64 {
37 set.iter()
38 .scan(0, |s, &x| {
39 *s = self.hash(*s, x);
40 Some(*s)
41 })
42 .last()
43 .unwrap()
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use std::collections::HashSet;
51 #[test]
52 fn test() {
53 let mut zh = ZobristHash::new();
54 let v = vec![1, 2, 3, 4, 5];
55 let hash_vec = zh.hash_vec_from_vec(&v);
56
57 assert_eq!(hash_vec.len(), 5);
58 assert_eq!(hash_vec[0], zh.hash_from_set(&to_set(1, &v)));
59 assert_eq!(hash_vec[1], zh.hash_from_set(&to_set(2, &v)));
60 assert_eq!(hash_vec[2], zh.hash_from_set(&to_set(3, &v)));
61 assert_eq!(hash_vec[3], zh.hash_from_set(&to_set(4, &v)));
62 assert_eq!(hash_vec[4], zh.hash_from_set(&to_set(5, &v)));
63 }
64 fn to_set(n: usize, v: &[i32]) -> HashSet<i32> {
65 v.iter().cloned().take(n).collect::<HashSet<_>>()
66 }
67 #[test]
68 fn rand() {
69 let mut rand = XorShift::<u64>::new();
70
71 let v = (0..10000).map(|_| rand.next().unwrap()).collect::<Vec<_>>();
72 let mut vv = v.clone();
73 vv.sort_unstable();
74 let mut zh = ZobristHash::new();
75 assert_eq!(
76 zh.hash_from_set(&v.into_iter().collect::<HashSet::<_>>()),
77 zh.hash_from_set(&vv.into_iter().collect::<HashSet::<_>>())
78 );
79 }
80}