|
18 | 18 | * e.g. in move and unmove and avoids recomputing the hash. |
19 | 19 | */ |
20 | 20 | namespace zobrist { |
21 | | - extern U64 squares[64][2][6]; |
22 | | - extern U64 side; |
23 | | - extern U64 ep[64]; |
24 | | - extern U64 castle[2][2]; |
| 21 | + // SplitMix64 PRNG (public domain) |
| 22 | + struct split_mix_64_state { uint64_t x; }; |
| 23 | + constexpr uint64_t split_mix_64(split_mix_64_state &state) { |
| 24 | + uint64_t z = (state.x += 0x9e3779b97f4a7c15); |
| 25 | + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; |
| 26 | + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; |
| 27 | + return z ^ (z >> 31); |
| 28 | + } |
25 | 29 |
|
26 | | - /** |
27 | | - * Initialise the hash arrays |
28 | | - */ |
29 | | - void init_hashes(); |
| 30 | + // Deterministically generates a random n-dimensional array of uint64_t at compile time |
| 31 | + // Uses variadic templates and recursion to generate the nested array type |
| 32 | + template<int Size, int... Rest> |
| 33 | + constexpr auto random_array(split_mix_64_state &state) { |
| 34 | + if constexpr (sizeof...(Rest) != 0) { |
| 35 | + std::array<decltype(random_array<Rest...>(state)), Size> arr = {}; |
| 36 | + for (int i = 0; i < Size; ++i) { |
| 37 | + arr[i] = random_array<Rest...>(state); |
| 38 | + } |
| 39 | + return arr; |
| 40 | + } else { |
| 41 | + std::array<uint64_t, Size> arr = {}; |
| 42 | + for (int i = 0; i < Size; ++i) { |
| 43 | + arr[i] = split_mix_64(state); |
| 44 | + } |
| 45 | + return arr; |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + template<int... Dims> |
| 50 | + constexpr auto random_array(uint64_t seed) { |
| 51 | + split_mix_64_state state { seed }; |
| 52 | + return random_array<Dims...>(state); |
| 53 | + } |
| 54 | + |
| 55 | + constexpr auto random_uint(uint64_t seed) { |
| 56 | + split_mix_64_state state { seed }; |
| 57 | + return split_mix_64(state); |
| 58 | + } |
| 59 | + |
| 60 | + inline constexpr auto squares = random_array<64, 2, 6>(0); |
| 61 | + inline constexpr auto side = random_uint(1); |
| 62 | + inline constexpr auto ep = random_array<64>(2); |
| 63 | + inline constexpr auto castle = random_array<2, 2>(3); |
30 | 64 | } |
31 | 65 |
|
32 | 66 | /** |
@@ -59,16 +93,16 @@ class material_data_t { |
59 | 93 | } |
60 | 94 |
|
61 | 95 | // Accessors |
62 | | - [[nodiscard]] inline int count(Team team, Piece piece) const { return counts[team][piece]; } |
63 | | - [[nodiscard]] inline U64 hash() const { return z_hash; } |
| 96 | + [[nodiscard]] constexpr int count(Team team, Piece piece) const { return counts[team][piece]; } |
| 97 | + [[nodiscard]] constexpr U64 hash() const { return z_hash; } |
64 | 98 |
|
65 | | - inline void inc(Team team, Piece piece) { |
| 99 | + constexpr void inc(Team team, Piece piece) { |
66 | 100 | // We reuse piece-square hashes for material hashing. The square used corresponds to the count |
67 | 101 | // e.g. the first pawn has the hash of a pawn on square 0, the second on square 1, etc. |
68 | 102 | z_hash ^= zobrist::squares[counts[team][piece]++][team][piece]; |
69 | 103 | assert(counts[team][piece] >= 0); |
70 | 104 | } |
71 | | - inline void dec(Team team, Piece piece) { |
| 105 | + constexpr void dec(Team team, Piece piece) { |
72 | 106 | // Note the prefix instead of postfix operator here. |
73 | 107 | z_hash ^= zobrist::squares[--counts[team][piece]][team][piece]; |
74 | 108 | assert(counts[team][piece] >= 0); |
|
0 commit comments