xiangting/standard/
hash.rs1use super::shupai_table::SHUPAI_TABLE;
6use super::wanzi_19_table::WANZI_19_TABLE;
7use super::zipai_table::ZIPAI_TABLE;
8
9pub fn hash_shupai(single_color_bingpai: &[u8]) -> usize {
10 let (hash, _) = single_color_bingpai
11 .iter()
12 .enumerate()
13 .fold((0, 0), |(h, n), (i, &c)| {
14 debug_assert!(i < 9);
15 debug_assert!(c <= 4);
16 debug_assert!(n + c <= 14);
17 let updated_n = n + c;
18 let updated_h = h + SHUPAI_TABLE[i][updated_n as usize][c as usize];
19 (updated_h, updated_n)
20 });
21 hash
22}
23
24pub fn hash_zipai(zipai_bingpai: &[u8]) -> usize {
25 let (hash, _) = zipai_bingpai
26 .iter()
27 .enumerate()
28 .fold((0, 0), |(h, n), (i, &c)| {
29 debug_assert!(i < 7);
30 debug_assert!(c <= 4);
31 debug_assert!(n + c <= 14);
32 let updated_n = n + c;
33 let updated_h = h + ZIPAI_TABLE[i][updated_n as usize][c as usize];
34 (updated_h, updated_n)
35 });
36 hash
37}
38
39pub fn hash_19m(wanzi_bingpai: &[u8]) -> usize {
40 let (hash, _) = wanzi_bingpai
41 .iter()
42 .step_by(8)
43 .enumerate()
44 .fold((0, 0), |(h, n), (i, &c)| {
45 debug_assert!(i < 2);
46 debug_assert!(c <= 4);
47 debug_assert!(n + c <= 8);
48 let updated_n = n + c;
49 let updated_h = h + WANZI_19_TABLE[i][updated_n as usize][c as usize];
50 (updated_h, updated_n)
51 });
52 hash
53}
54
55#[cfg(test)]
56mod tests {
57 use super::super::shupai_table::SHUPAI_SIZE;
58 use super::super::wanzi_19_table::WANZI_19_SIZE;
59 use super::super::zipai_table::ZIPAI_SIZE;
60 use super::*;
61
62 fn test_hash<const N: usize>(hand: &[u8; N], check: &mut [u8]) {
63 let h = match N {
64 9 => {
65 let h = hash_shupai(hand);
66 assert!(h < SHUPAI_SIZE, "Out of range.");
67 h
68 }
69 7 => {
70 let h = hash_zipai(hand);
71 assert!(h < ZIPAI_SIZE, "Out of range.");
72 h
73 }
74 2 => {
75 let full_hand = [hand[0], 0, 0, 0, 0, 0, 0, 0, hand[1]];
76 let h = hash_19m(&full_hand);
77 assert!(h < WANZI_19_SIZE, "Out of range.");
78 h
79 }
80 _ => unreachable!(),
81 };
82
83 assert!(check[h] == 0, "Collision.");
84 check[h] += 1;
85 }
86
87 fn build_hand<const N: usize>(i: usize, hand: &mut [u8; N], n: u8, check: &mut [u8]) {
88 assert!([9, 7, 2].contains(&N));
89 assert!(i <= N);
90 assert!(n <= 14);
91
92 if i == N {
93 test_hash(hand, check);
94 return;
95 }
96
97 assert!(hand[i] == 0);
98
99 for c in 0..=4 {
100 if n + c > 14 {
101 break;
102 }
103 hand[i] = c;
104 build_hand(i + 1, hand, n + c, check);
105 hand[i] = 0;
106 }
107 }
108
109 #[test]
110 fn test_hash_shupai() {
111 let mut hand = [0u8; 9];
112 let mut check = [0u8; SHUPAI_SIZE];
113 build_hand(0, &mut hand, 0, &mut check);
114 assert!(check.iter().all(|&c| c == 1), "A logic error.");
115 }
116
117 #[test]
118 fn test_hash_zipai() {
119 let mut hand = [0u8; 7];
120 let mut check = [0u8; ZIPAI_SIZE];
121 build_hand(0, &mut hand, 0, &mut check);
122 assert!(check.iter().all(|&c| c == 1), "A logic error.");
123 }
124
125 #[test]
126 fn test_hash_19m() {
127 let mut hand = [0u8; 2];
128 let mut check = [0u8; WANZI_19_SIZE];
129 build_hand(0, &mut hand, 0, &mut check);
130 assert!(check.iter().all(|&c| c == 1), "A logic error.");
131 }
132}