Skip to content

Commit d30b007

Browse files
committed
Compile time generation of zobrist hashes
1 parent 38ec0b3 commit d30b007

File tree

9 files changed

+50
-68
lines changed

9 files changed

+50
-68
lines changed

bb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* @param square bit to set
2222
* @return bitboard with the bit at {@code square} set
2323
*/
24-
inline U64 single_bit(uint8_t square) {
24+
constexpr U64 single_bit(uint8_t square) {
2525
return 0x1ull << square;
2626
}
2727

hash.cpp

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,6 @@
77
#include <cstring>
88
#include "hash.h"
99

10-
/*
11-
* Concrete fields and initialisation code - see hash.h for more info on Zobrist hashing
12-
*/
13-
namespace zobrist {
14-
const U64 seed = 0xBEEF;
15-
16-
U64 squares[64][2][6];
17-
U64 side;
18-
U64 ep[64];
19-
U64 castle[2][2];
20-
21-
void init_hashes() {
22-
std::mt19937_64 gen(seed); // NOLINT(cert-msc51-cpp) - constant seed intended
23-
std::uniform_int_distribution<U64> dist;
24-
25-
side = dist(gen);
26-
castle[0][0] = dist(gen);
27-
castle[0][1] = dist(gen);
28-
castle[1][0] = dist(gen);
29-
castle[1][1] = dist(gen);
30-
31-
for (int i = 0; i < 64; i++) {
32-
for (int j = 0; j < 2; j++)
33-
for (int k = 0; k < 6; k++)
34-
squares[i][j][k] = dist(gen);
35-
ep[i] = dist(gen);
36-
}
37-
}
38-
}
39-
4010
tt::hash_t::hash_t(size_t size) {
4111
// Divide size by the sizeof an entry
4212
size /= (sizeof(tt::entry_t) * bucket_size);

hash.h

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,49 @@
1818
* e.g. in move and unmove and avoids recomputing the hash.
1919
*/
2020
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+
}
2529

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);
3064
}
3165

3266
/**
@@ -59,16 +93,16 @@ class material_data_t {
5993
}
6094

6195
// 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; }
6498

65-
inline void inc(Team team, Piece piece) {
99+
constexpr void inc(Team team, Piece piece) {
66100
// We reuse piece-square hashes for material hashing. The square used corresponds to the count
67101
// e.g. the first pawn has the hash of a pawn on square 0, the second on square 1, etc.
68102
z_hash ^= zobrist::squares[counts[team][piece]++][team][piece];
69103
assert(counts[team][piece] >= 0);
70104
}
71-
inline void dec(Team team, Piece piece) {
105+
constexpr void dec(Team team, Piece piece) {
72106
// Note the prefix instead of postfix operator here.
73107
z_hash ^= zobrist::squares[--counts[team][piece]][team][piece];
74108
assert(counts[team][piece] >= 0);

main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ U64 perft(board_t &, int);
1414
int main(int argc, char *argv[]) {
1515
// Initialise engine
1616
init_tables();
17-
zobrist::init_hashes();
1817
evaluator_t::eval_init();
1918

2019
// Board

movesort.cpp

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ move_t movesort_t::next(GenStage &stage, int &score, bool skip_quiets) {
4848
}
4949
}
5050

51-
buf_swap_capt(best_idx, capt_idx);
51+
std::swap(capt_buf[best_idx], capt_buf[capt_idx]);
5252

5353
if (capt_buf[capt_idx] == hash_move) {
5454
capt_idx++;
@@ -96,7 +96,8 @@ move_t movesort_t::next(GenStage &stage, int &score, bool skip_quiets) {
9696
best_main_idx = i;
9797
}
9898
}
99-
buf_swap_main(best_main_idx, main_idx);
99+
std::swap(main_scores[best_main_idx], main_scores[main_idx]);
100+
std::swap(main_buf[best_main_idx], main_buf[main_idx]);
100101

101102
if (main_buf[main_idx] == hash_move) {
102103
main_idx++;
@@ -126,22 +127,6 @@ move_t movesort_t::next(GenStage &stage, int &score, bool skip_quiets) {
126127
}
127128
}
128129

129-
void movesort_t::buf_swap_main(int a, int b) {
130-
move_t temp = main_buf[a];
131-
main_buf[a] = main_buf[b];
132-
main_buf[b] = temp;
133-
134-
int score = main_scores[a];
135-
main_scores[a] = main_scores[b];
136-
main_scores[b] = score;
137-
}
138-
139-
void movesort_t::buf_swap_capt(int a, int b) {
140-
move_t temp = capt_buf[a];
141-
capt_buf[a] = capt_buf[b];
142-
capt_buf[b] = temp;
143-
}
144-
145130
move_t *movesort_t::generated_quiets(size_t &count) {
146131
count = main_idx;
147132
return main_buf;

movesort.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ class movesort_t {
7676

7777
move_t killer_1, killer_2, killer_3;
7878

79-
void buf_swap_main(int a, int b);
80-
void buf_swap_capt(int a, int b);
81-
8279
movegen_t gen;
8380

8481
int main_idx = 0;

testing/runner.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
int main(int argc, char* argv[]) {
1313
init_tables();
14-
zobrist::init_hashes();
1514
evaluator_t::eval_init();
1615

1716
return Catch::Session().run(argc, argv);

texeltuning/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ double get_result(const std::string &result) {
2626
int main(int argc, char *argv[]) {
2727
// Initialise engine
2828
init_tables();
29-
zobrist::init_hashes();
3029
evaluator_t::eval_init();
3130

3231
// Startup

toppletuning/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ void print_params(const eval_params_t &current_params);
1010
int main(int argc, char *argv[]) {
1111
// Initialise engine
1212
init_tables();
13-
zobrist::init_hashes();
1413
evaluator_t::eval_init();
1514

1615
std::cout << "total parameters: " << sizeof(eval_params_t) / sizeof(int) << std::endl;

0 commit comments

Comments
 (0)