Skip to content

Commit d810b27

Browse files
authored
Merge pull request #26 from konsolas/king-safety
Search improvements and bugfixes
2 parents 9579fc2 + 49f1d6e commit d810b27

File tree

21 files changed

+458
-410
lines changed

21 files changed

+458
-410
lines changed

CMakeLists.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
cmake_minimum_required(VERSION 3.8)
1+
cmake_minimum_required(VERSION 3.9)
22
project(Topple)
33

44
set(CMAKE_CXX_STANDARD 17)
5-
set(TOPPLE_VERSION 0.7.0)
5+
set(TOPPLE_VERSION 0.7.1)
66

77
# Source files for different targets
88
set(SOURCE_FILES
@@ -23,7 +23,8 @@ set(TEST_FILES testing/catch.hpp testing/runner.cpp testing/util.h testing/util.
2323
testing/tests/test_bb.cpp
2424
testing/tests/test_board.cpp
2525
testing/tests/test_perft.cpp
26-
testing/tests/test_see.cpp)
26+
testing/tests/test_see.cpp
27+
testing/tests/test_hash.cpp)
2728
set(TUNE_FILES tuning/tunemain.cpp tuning/tuner.cpp tuning/tuner.h)
2829

2930
# Add version definitions
@@ -57,7 +58,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release")
5758
add_executable(Topple_${TOPPLE_VERSION}_legacy ${SOURCE_FILES} main.cpp)
5859
target_compile_options(Topple_${TOPPLE_VERSION}_legacy PUBLIC -s)
5960
add_dependencies(Release Topple_${TOPPLE_VERSION}_legacy)
60-
foreach(RELEASE_ARCH core2 nehalem westmere sandybridge ivybridge haswell broadwell skylake znver1 bdver4)
61+
foreach(RELEASE_ARCH core2 nehalem westmere sandybridge ivybridge haswell broadwell skylake bdver4 znver1 znver2)
6162
add_executable(Topple_${TOPPLE_VERSION}_${RELEASE_ARCH} ${SOURCE_FILES} main.cpp)
6263
target_compile_options(Topple_${TOPPLE_VERSION}_${RELEASE_ARCH} PUBLIC -s -march=${RELEASE_ARCH})
6364
add_dependencies(Release Topple_${TOPPLE_VERSION}_${RELEASE_ARCH})

board.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ move_t board_t::to_move(packed_move_t packed_move) const {
328328
move.info.captured_type = sq_data[move.info.to].occupied ? sq_data[move.info.to].piece : 0;
329329

330330
// Promotion
331-
move.info.is_promotion = static_cast<uint16_t>(packed_move.type != 0);
331+
move.info.is_promotion = static_cast<uint16_t>(packed_move.type != 0 && (move.info.to <= H1 || move.info.to >= A8));
332332
if (move.info.is_promotion) {
333333
move.info.promotion_type = packed_move.type;
334334
}
@@ -347,7 +347,7 @@ move_t board_t::to_move(packed_move_t packed_move) const {
347347
}
348348

349349
// EP
350-
move.info.is_ep = static_cast<uint16_t>(record[now].ep_square != 0
350+
move.info.is_capture |= move.info.is_ep = static_cast<uint16_t>(record[now].ep_square != 0
351351
&& move.info.piece == PAWN
352352
&& move.info.to == record[now].ep_square);
353353

@@ -462,6 +462,12 @@ bool board_t::is_pseudo_legal(move_t move) const {
462462
}
463463
}
464464

465+
if(move.info.piece == PAWN) {
466+
if ((move.info.to <= H1 || move.info.to >= A8) == !move.info.is_promotion) return false;
467+
} else {
468+
if (move.info.is_promotion) return false;
469+
}
470+
465471
return (bb_pieces[team][move.info.piece] & single_bit(move.info.from)) &&
466472
!(bb_side[team] & single_bit(move.info.to));
467473
}

board.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct sq_data_t {
4646
* Internal board representation used in the Topple engine.
4747
* Uses bitboard representation only
4848
*/
49-
struct board_t {
49+
struct alignas(64) board_t {
5050
board_t() = default;
5151
explicit board_t(const std::string &fen);
5252

eval.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,7 @@ struct processed_params_t : public eval_params_t {
197197
int kat_table[128] = {};
198198
};
199199

200-
class evaluator_t {
201-
friend class pawns::structure_t;
202-
200+
class alignas(64) evaluator_t {
203201
size_t pawn_hash_entries;
204202
std::vector<pawns::structure_t> pawn_hash_table;
205203

hash.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//
44

55
#include <random>
6+
#include <memory>
67
#include <cstring>
78
#include "hash.h"
89

@@ -53,14 +54,14 @@ bool tt::hash_t::probe(U64 hash, tt::entry_t &entry) {
5354
const size_t index = (hash & num_entries) * bucket_size;
5455
tt::entry_t *bucket = table + index;
5556

56-
if(bucket->hash == hash) {
57+
if((bucket->coded_hash ^ bucket->data) == hash) {
5758
bucket->refresh(generation);
5859
entry = *bucket;
5960
return true;
6061
}
6162

6263
for(size_t i = 1; i < bucket_size; i++) {
63-
if((bucket + i)->hash == hash) {
64+
if(((bucket + i)->coded_hash ^ (bucket + i)->data) == hash) {
6465
(bucket + i)->refresh(generation);
6566
entry = *(bucket + i);
6667
return true;
@@ -87,34 +88,40 @@ void tt::hash_t::save(Bound bound, U64 hash, int depth, int ply, int static_eval
8788
if (score >= MINCHECKMATE) score += ply;
8889
if (score <= -MINCHECKMATE) score -= ply;
8990

90-
if(bucket->hash == hash) {
91+
tt::entry_t updated = {};
92+
updated.info.move = compress(move);
93+
updated.info.static_eval = static_cast<int16_t>(static_eval);
94+
updated.info.internal_value = static_cast<int16_t>(score);
95+
updated.info.about = uint16_t(bound) | (uint16_t(depth) << 2u) | (generation << 10u);
96+
updated.coded_hash = hash ^ updated.data;
97+
98+
if((bucket->coded_hash ^ bucket->data) == hash) {
9199
if(bound == EXACT || depth >= bucket->depth() - 2) {
92-
bucket->update(bound, depth, generation, move, static_eval, score);
100+
*bucket = updated;
93101
}
94102
return;
95103
}
96104

97105
tt::entry_t *replace = bucket;
98106
for(size_t i = 1; i < bucket_size; i++) {
99107
// Always replace if same position
100-
if((bucket + i)->hash == hash) {
108+
if(((bucket + i)->coded_hash ^ (bucket + i)->data) == hash) {
101109
if(bound == EXACT || depth >= bucket->depth() - 2) {
102-
(bucket + i)->update(bound, depth, generation, move, static_eval, score);
110+
*(bucket + i) = updated;
103111
}
104112
return;
105-
} else if((bucket + i)->about < replace->about) {
113+
} else if((bucket + i)->info.about < replace->info.about) {
106114
replace = (bucket + i);
107115
}
108116
}
109117

110118
// Replace best candidate
111-
replace->hash = hash;
112-
replace->update(bound, depth, generation, move, static_eval, score);
119+
*replace = updated;
113120
}
114121

115122
void tt::hash_t::age() {
116123
generation++;
117-
if(generation >= 127) {
124+
if(generation >= 63) {
118125
generation = 1;
119126

120127
// Clear up hash
@@ -125,12 +132,17 @@ void tt::hash_t::age() {
125132
}
126133

127134
size_t tt::hash_t::hash_full() {
135+
constexpr size_t sample_size = 4000;
136+
constexpr size_t divisor = sample_size / 1000;
137+
138+
assert(num_entries * bucket_size > sample_size);
139+
128140
size_t cnt = 0;
129-
for (size_t i = 0; i < num_entries * bucket_size; i++) {
141+
for (size_t i = 0; i < sample_size; i++) {
130142
if (table[i].generation() == generation) {
131143
cnt++;
132144
}
133145
}
134146

135-
return (cnt * 1000) / (num_entries * bucket_size);
147+
return cnt / divisor;
136148
}

hash.h

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef TOPPLE_HASH_H
66
#define TOPPLE_HASH_H
77

8+
#include <mutex>
9+
810
#include "types.h"
911
#include "move.h"
1012

@@ -133,43 +135,44 @@ namespace tt {
133135
}
134136

135137
struct entry_t { // 16 bytes
136-
U64 hash; // 8 bytes
137-
packed_move_t move; // 2 bytes
138-
int16_t static_eval; // 2 bytes
139-
int16_t internal_value; // 2 bytes
140-
uint16_t about; // 2 bytes [GGGGGGGDDDDDDDBB] // 7 bits generation, 7 bits depth, 2 bits bound
141-
142-
int value(int ply) {
143-
if (internal_value >= MINCHECKMATE) {
144-
return internal_value - ply;
145-
} else if (internal_value <= -MINCHECKMATE) {
146-
return internal_value + ply;
138+
U64 coded_hash; // 8 bytes
139+
union {
140+
struct {
141+
packed_move_t move;
142+
int16_t static_eval;
143+
int16_t internal_value;
144+
uint16_t about; // 6G 8D 2B
145+
} info;
146+
147+
U64 data;
148+
};
149+
150+
int value(int ply) const {
151+
if (info.internal_value >= MINCHECKMATE) {
152+
return info.internal_value - ply;
153+
} else if (info.internal_value <= -MINCHECKMATE) {
154+
return info.internal_value + ply;
147155
} else {
148-
return internal_value;
156+
return info.internal_value;
149157
}
150158
}
151159

152160
inline Bound bound() {
153-
return Bound(about & EXACT);
161+
return Bound(info.about & 3u);
154162
}
155163

156164
inline int depth() {
157-
return (about >> 2) & 127;
158-
}
159-
160-
inline int generation() {
161-
return about >> 9;
165+
return (info.about >> 2u) & 255u;
162166
}
163167

164-
void update(Bound bound, int depth, int generation, move_t best_move, int eval, int score) {
165-
about = bound | (depth << 2) | (generation << 9);
166-
move = compress(best_move);
167-
static_eval = static_cast<int16_t>(eval);
168-
internal_value = static_cast<int16_t>(score);
168+
inline unsigned generation() {
169+
return info.about >> 10u;
169170
}
170171

171-
void refresh(int gen) {
172-
about = uint16_t((about & 511) | (gen << 9));
172+
void refresh(unsigned gen) {
173+
U64 original = coded_hash ^ data;
174+
info.about = uint16_t((info.about & 1023u) | (gen << 10u));
175+
coded_hash = original ^ data;
173176
}
174177
};
175178

@@ -186,8 +189,8 @@ namespace tt {
186189
size_t hash_full();
187190
private:
188191
size_t num_entries;
192+
unsigned generation = 1;
189193
entry_t *table;
190-
uint8_t generation = 1;
191194
};
192195
}
193196

0 commit comments

Comments
 (0)