-
Notifications
You must be signed in to change notification settings - Fork 0
/
tbconfig.h
451 lines (406 loc) · 14.9 KB
/
tbconfig.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
* tbconfig.h
* (C) 2015 basil, all rights reserved,
* Modifications Copyright 2016-2017 Jon Dart
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef TBCONFIG_H
#define TBCONFIG_H
#include <cstdint>
/****************************************************************************/
/* BUILD CONFIG: */
/****************************************************************************/
/*
* Define TB_CUSTOM_POP_COUNT to override the internal popcount
* implementation. To do this supply a macro or function definition
* here:
*/
#define TB_CUSTOM_POP_COUNT(x) bitmask::count_bits(x)
/*
* Define TB_CUSTOM_LSB to override the internal lsb
* implementation. To do this supply a macro or function definition
* here:
*/
#define TB_CUSTOM_LSB(x) bitmask::log2_lsb(x)
/*
* Define TB_NO_STDINT if you do not want to use <stdint.h> or it is not
* available.
*/
/* #define TB_NO_STDINT */
/*
* Define TB_NO_STDBOOL if you do not want to use <stdbool.h> or it is not
* available or unnecessary (e.g. C++).
*/
/* #define TB_NO_STDBOOL */
/*
* Define TB_NO_THREADS if your program is not multi-threaded.
*/
#define TB_NO_THREADS
/*
* Define TB_NO_HELPER_API if you do not need the helper API.
*/
#define TB_NO_HELPER_API
/*
* Define TB_NO_HW_POP_COUNT if there is no hardware popcount instruction.
*
* Note: if defined, TB_CUSTOM_POP_COUNT is always used in preference
* to any built-in popcount functions.
*
* If no custom popcount function is defined, and if the following
* define is not set, the code will attempt to use an available hardware
* popcnt (currently supported on x86_64 architecture only) and otherwise
* will fall back to a software implementation.
*/
/* #define TB_NO_HW_POP_COUNT */
/***************************************************************************/
/* SCORING CONSTANTS */
/***************************************************************************/
/*
* Fathom can produce scores for tablebase moves. These depend on the
* value of a pawn, and the magnitude of mate scores. The following
* constants are representative values but will likely need
* modification to adapt to an engine's own internal score values.
*/
//#define TB_VALUE_FPAWN 100 /* value of pawn in endgame */
//#define TB_VALUE_MATE 32000
//#define TB_VALUE_INFINITE 32767 /* value above all normal score values */
#define TB_VALUE_DRAW 0
//#define TB_MAX_MATE_PLY 255
extern const int32_t TB_VALUE_FPAWN;
extern const int32_t TB_VALUE_MATE;
extern const int32_t TB_VALUE_INFINITE;
extern const int32_t TB_MAX_MATE_PLY;
/***************************************************************************/
/* ENGINE INTEGRATION CONFIG */
/***************************************************************************/
/*
* If you are integrating tbprobe into an engine, you can replace some of
* tbprobe's built-in functionality with that already provided by the engine.
* This is OPTIONAL. If no definition are provided then tbprobe will use its
* own internal defaults. That said, for engines it is generally a good idea
* to avoid redundancy.
*/
#include <Piece.hpp>
/*
* Define TB_KING_ATTACKS(square) to return the king attacks bitboard for a
* king at `square'.
*/
#define TB_KING_ATTACKS(square) piece::get_king_attack((pos_t)(square))
/*
* Define TB_KNIGHT_ATTACKS(square) to return the knight attacks bitboard for
* a knight at `square'.
*/
#define TB_KNIGHT_ATTACKS(square) piece::get_knight_attack((pos_t)(square))
/*
* Define TB_ROOK_ATTACKS(square, occ) to return the rook attacks bitboard
* for a rook at `square' assuming the given `occ' occupancy bitboard.
*/
#define TB_ROOK_ATTACKS(square, occ) piece::get_sliding_orth_attack((pos_t)(square), (piece_bitboard_t)(occ))
/*
* Define TB_BISHOP_ATTACKS(square, occ) to return the bishop attacks bitboard
* for a bishop at `square' assuming the given `occ' occupancy bitboard.
*/
#define TB_BISHOP_ATTACKS(square, occ) piece::get_sliding_diag_attack((pos_t)(square), (piece_bitboard_t)(occ))
/*
* Define TB_QUEEN_ATTACKS(square, occ) to return the queen attacks bitboard
* for a queen at `square' assuming the given `occ' occupancy bitboard.
* NOTE: If no definition is provided then tbprobe will use:
* TB_ROOK_ATTACKS(square, occ) | TB_BISHOP_ATTACKS(square, occ)
*/
/* #define TB_QUEEN_ATTACKS(square, occ) <DEFINITION> */
/*
* Define TB_PAWN_ATTACKS(square, color) to return the pawn attacks bitboard
* for a `color' pawn at `square'.
* NOTE: This definition must work for pawns on ranks 1 and 8. For example,
* a white pawn on e1 attacks d2 and f2. A black pawn on e1 attacks
* nothing. Etc.
* NOTE: This definition must not include en passant captures.
*/
#define TB_PAWN_ATTACKS(square, color) piece::get_pawn_attack((pos_t)(square), color ? WHITE : BLACK)
#include <external/fathom/src/tbprobe.c>
#include <Board.hpp>
namespace tb {
INLINE bool init(const std::string &syzygy_path="external/syzygy/src"s) {
return tb_init(syzygy_path.c_str());
}
INLINE void free() {
tb_free();
}
INLINE move_t u16_to_move_t(uint16_t tb_move) {
const pos_t i = TB_MOVE_FROM(tb_move);
const pos_t _j = TB_MOVE_TO(tb_move);
pos_t promote = 0x00;
switch(TB_MOVE_PROMOTES(tb_move)) {
case TB_PROMOTES_FKNIGHT:promote=board::PROMOTE_KNIGHT;break;
case TB_PROMOTES_FBISHOP:promote=board::PROMOTE_BISHOP;break;
case TB_PROMOTES_FROOK: promote=board::PROMOTE_ROOK;break;
case TB_PROMOTES_FQUEEN: promote=board::PROMOTE_QUEEN;break;
}
move_t m = bitmask::_pos_pair(i, _j | promote);
return m;
}
INLINE move_t u_to_move_t(unsigned result) {
const pos_t i = TB_GET_FROM(result);
const pos_t _j = TB_GET_TO(result);
pos_t promote = 0x00;
switch(TB_GET_PROMOTES(result)) {
case TB_PROMOTES_FKNIGHT:promote=board::PROMOTE_KNIGHT;break;
case TB_PROMOTES_FBISHOP:promote=board::PROMOTE_BISHOP;break;
case TB_PROMOTES_FROOK: promote=board::PROMOTE_ROOK;break;
case TB_PROMOTES_FQUEEN: promote=board::PROMOTE_QUEEN;break;
}
move_t m = bitmask::_pos_pair(i, _j | promote);
return m;
}
// above preprocessor definitions should produce a correct
// material score (no heuristics)
INLINE auto score_of(const TbRootMove &tb_root_move) {
auto sc = tb_root_move.tbScore;
if(std::abs(sc) >= TB_VALUE_MATE - 16000) {
const decltype(sc) sc_mate = TB_VALUE_MATE - tb_root_move.pvSize;
sc = (sc < 0) ? -sc_mate : sc_mate;
}
return sc;
}
INLINE bool can_probe(const Board &b) {
return (TB_LARGEST > 0) && !(
b.crazyhouse || (
b.chess960
&& b.get_castlings_rook_mask() != bitmask::_pos_pair(0x00, 0x00))
|| piece::size(b.bits[WHITE] | b.bits[BLACK]) > TB_LARGEST
// anything except castlings == 0x00 is rejected
//|| b.get_castlings_rook_mask() != bitmask::_pos_pair(0x00, 0x00)
);
}
namespace internal {
INLINE unsigned _get_enpassant(const Board &b) {
return (b.enpassant_trace() == board::nopos) ? 0 : b.enpassant_trace();
}
INLINE bool _get_turn(const Board &b) {
return (b.activePlayer() == WHITE);
}
INLINE unsigned _get_castlings(const Board &b) {
// anything except castlings == 0x00 is rejected
assert(b.get_castlings_rook_mask() == bitmask::_pos_pair(0x00, 0x00));
return 0x00;
}
MoveLine _get_rootmove_pline(TbRootMove &tb_root_move) {
MoveLine mline;
for(size_t i = 0; i < tb_root_move.pvSize; ++i) {
mline.put(tb::u16_to_move_t(tb_root_move.pv[i]));
}
return mline;
}
const char *_wdl_to_name_str[5] =
{
"loss",
"blessed_loss",
"draw",
"cursed_win",
"win"
};
template <typename F>
void _foreach_tbrootmoves(TbRootMoves &tb_root_moves, F &&func) {
for(size_t m_index = 0; m_index < tb_root_moves.size; ++m_index) {
TbRootMove tb_root_move = tb_root_moves.moves[m_index];
const move_t m = tb::u16_to_move_t(tb_root_move.move);
// func(m, tb::score_of(tb_root_move), tb_root_move.tbRank, [=]() mutable -> MoveLine {
// return tb::internal::_get_rootmove_pline(tb_root_move);;
// });
func(m, tb::score_of(tb_root_move), tb_root_move.tbRank);
}
}
} // namespace internal
std::string wdl_to_str(const Board &b, unsigned wdl) {
return tb::internal::_wdl_to_name_str[(tb::internal::_get_turn(b)? wdl: 4-wdl)];
}
int8_t probe_wdl(const Board &b) {
assert(tb::can_probe(b));
const ply_index_t halfmoves = 0;
unsigned result = tb_probe_wdl(
b.bits[WHITE], b.bits[BLACK], b.get_king_bits(),
b.bits_slid_diag & b.bits_slid_orth,
b.bits_slid_orth & ~b.bits_slid_diag,
b.bits_slid_diag & ~b.bits_slid_orth,
b.get_knight_bits(), b.bits_pawns,
0, // anything except halfmoves == 0 is rejected
tb::internal::_get_castlings(b),
tb::internal::_get_enpassant(b),
tb::internal::_get_turn(b)
);
if(result == TB_RESULT_FAILED) {
return -1;
}
return TB_GET_WDL(result);
}
std::string probe_wdl_s(const Board &b) {
int8_t res = tb::probe_wdl(b);
if(res == -1) {
return "failed"s;
}
return tb::wdl_to_str(b, res);
}
template <typename F>
INLINE int8_t probe_root_dtz(const Board &b, F &&func) {
assert(tb::can_probe(b));
//assert(tb::probe_wdl(b) != -1);
TbRootMoves result;
memset(&result, 0x00, sizeof(result));
result.size = 0;
// TODO?
const bool has_repeated = true;
// score will be corrected by the engine, so better not lose hope
const bool use_rule50 = true;
const int ret = tb_probe_root_dtz(
b.bits[WHITE], b.bits[BLACK], b.get_king_bits(),
b.bits_slid_diag & b.bits_slid_orth,
b.bits_slid_orth & ~b.bits_slid_diag,
b.bits_slid_diag & ~b.bits_slid_orth,
b.get_knight_bits(), b.bits_pawns,
b.get_halfmoves() + 1,
tb::internal::_get_castlings(b),
tb::internal::_get_enpassant(b),
tb::internal::_get_turn(b),
has_repeated, use_rule50,
&result
);
if(ret == 0)return -1;
tb::internal::_foreach_tbrootmoves(result, std::forward<F>(func));
return 0;
}
template <typename F>
INLINE int8_t probe_root_wdl(const Board &b, F &&func) {
assert(tb::can_probe(b));
bool use_rule50 = true;
TbRootMoves moveresults;
unsigned ret = tb_probe_root_wdl(
b.bits[WHITE], b.bits[BLACK], b.get_king_bits(),
b.bits_slid_diag & b.bits_slid_orth,
b.bits_slid_orth & ~b.bits_slid_diag,
b.bits_slid_diag & ~b.bits_slid_orth,
b.get_knight_bits(), b.bits_pawns,
b.get_halfmoves(), // anything except halfmoves == 0 is rejected
tb::internal::_get_castlings(b),
tb::internal::_get_enpassant(b),
tb::internal::_get_turn(b),
use_rule50,
&moveresults
);
if(ret == TB_RESULT_FAILED) {
return -1;
}
tb::internal::_foreach_tbrootmoves(moveresults, std::forward<F>(func));
return 0;
}
INLINE decltype(auto) get_ranked_moves(Board &b, bool prune=false) {
assert(tb::can_probe(b));
std::vector<std::pair<float, move_t>> tbmoves;
tbmoves.reserve(16);
ssize_t min_wdl = -1;
auto &&func = [&](move_t m, int32_t tbScore, int32_t tbRank) mutable -> void {
// if(prune && (min_tbrank < tbRank || (min_tbrank == tbRank && min_tbscore < tbScore))) {
ssize_t wdl = -1, dtz = 0;
float mval = .0;
if(tbRank > 900) {
wdl = TB_WIN; // 4
dtz = 1000 - tbRank;
mval = 900. - dtz;
} else if(tbRank > 800) {
wdl = TB_CURSED_WIN; // 3
dtz = 900 - tbRank;
mval = 500. - dtz;
} else if(tbRank < -900) {
wdl = TB_LOSS; // 0
dtz = -1000 - tbRank;
mval = -900. - dtz;
} else if(tbRank < -800) {
wdl = TB_BLESSED_LOSS; // 1
dtz = -900 - tbRank;
mval = -500. - dtz;
} else {
wdl = TB_DRAW; // 2
dtz = 0;
mval = .0;
}
if(prune && min_wdl < wdl) {
tbmoves.clear();
min_wdl = wdl;
}
if(!prune || min_wdl == wdl) {
tbmoves.emplace_back(mval, m);
}
};
int8_t ret = probe_root_dtz(b, func);
if(ret == -1) {
ret = probe_root_wdl(b, func);
}
return tbmoves;
}
template <typename F>
INLINE void probe_root(Board &b, F &&func) {
if(!tb::can_probe(b)) {
return;
}
unsigned moveresults[TB_MAX_MOVES];
unsigned result = tb_probe_root(
b.bits[WHITE], b.bits[BLACK], b.get_king_bits(),
b.bits_slid_diag & b.bits_slid_orth,
b.bits_slid_orth & ~b.bits_slid_diag,
b.bits_slid_diag & ~b.bits_slid_orth,
b.get_knight_bits(), b.bits_pawns,
b.get_halfmoves(),
tb::internal::_get_castlings(b),
tb::internal::_get_enpassant(b),
tb::internal::_get_turn(b),
moveresults
);
assert(result != TB_RESULT_FAILED);
if(result == TB_RESULT_CHECKMATE || result == TB_RESULT_STALEMATE) {
return;
}
// func(tb::u_to_move_t(result), TB_GET_WDL(result), TB_GET_DTZ(result));
for(size_t i = 0; moveresults[i] != TB_RESULT_FAILED; ++i) {
move_t m = tb::u_to_move_t(moveresults[i]);
func(m, TB_GET_WDL(moveresults[i]), TB_GET_DTZ(moveresults[i]));
}
}
INLINE move_t probe_root(const Board &b) {
assert(tb::can_probe(b));
unsigned result = tb_probe_root(
b.bits[WHITE], b.bits[BLACK], b.get_king_bits(),
b.bits_slid_diag & b.bits_slid_orth,
b.bits_slid_orth & ~b.bits_slid_diag,
b.bits_slid_diag & ~b.bits_slid_orth,
b.get_knight_bits(), b.bits_pawns,
b.get_halfmoves(), // anything except halfmoves == 0 is rejected
tb::internal::_get_castlings(b),
tb::internal::_get_enpassant(b),
tb::internal::_get_turn(b),
NULL
);
if(result == TB_RESULT_FAILED) {
return board::nullmove;
} else if(result == TB_RESULT_CHECKMATE || result == TB_RESULT_STALEMATE) {
return board::nullmove;
}
return tb::u_to_move_t(result);
}
} // namespace tb
#endif