Skip to content

Commit 1568303

Browse files
committed
Speed up kpk initialization
The trick is to classify more position at first cycle, so to reduce following work. Speed up is of about 50% ! Also some cleanup while there. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
1 parent 4c9d570 commit 1568303

File tree

2 files changed

+109
-122
lines changed

2 files changed

+109
-122
lines changed

src/bitbase.cpp

Lines changed: 107 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,17 @@ namespace {
2828
RESULT_UNKNOWN,
2929
RESULT_INVALID,
3030
RESULT_WIN,
31-
RESULT_LOSS,
3231
RESULT_DRAW
3332
};
3433

3534
struct KPKPosition {
35+
Result classify_knowns(int index);
36+
Result classify(int index, Result db[]);
37+
38+
private:
3639
void from_index(int index);
37-
bool is_legal() const;
38-
bool is_immediate_draw() const;
39-
bool is_immediate_win() const;
40+
Result classify_white(const Result db[]);
41+
Result classify_black(const Result db[]);
4042
Bitboard wk_attacks() const { return StepAttacksBB[WK][whiteKingSquare]; }
4143
Bitboard bk_attacks() const { return StepAttacksBB[BK][blackKingSquare]; }
4244
Bitboard pawn_attacks() const { return StepAttacksBB[WP][pawnSquare]; }
@@ -46,13 +48,11 @@ namespace {
4648
};
4749

4850
// The possible pawns squares are 24, the first 4 files and ranks from 2 to 7
49-
const int IndexMax = 2 * 24 * 64 * 64; // color * wp_sq * wk_sq * bk_sq
51+
const int IndexMax = 2 * 24 * 64 * 64; // color * wp_sq * wk_sq * bk_sq = 196608
5052

5153
// Each uint32_t stores results of 32 positions, one per bit
5254
uint32_t KPKBitbase[IndexMax / 32];
5355

54-
Result classify_wtm(const KPKPosition& pos, const Result bb[]);
55-
Result classify_btm(const KPKPosition& pos, const Result bb[]);
5656
int compute_index(Square wksq, Square bksq, Square wpsq, Color stm);
5757
}
5858

@@ -65,64 +65,49 @@ uint32_t probe_kpk_bitbase(Square wksq, Square wpsq, Square bksq, Color stm) {
6565
}
6666

6767

68-
void init_kpk_bitbase() {
68+
void kpk_bitbase_init() {
6969

70-
Result bb[IndexMax];
70+
Result db[IndexMax];
7171
KPKPosition pos;
72-
bool repeat;
72+
int index, bit, repeat = 1;
7373

7474
// Initialize table
75-
for (int i = 0; i < IndexMax; i++)
76-
{
77-
pos.from_index(i);
78-
bb[i] = !pos.is_legal() ? RESULT_INVALID
79-
: pos.is_immediate_draw() ? RESULT_DRAW
80-
: pos.is_immediate_win() ? RESULT_WIN : RESULT_UNKNOWN;
81-
}
75+
for (index = 0; index < IndexMax; index++)
76+
db[index] = pos.classify_knowns(index);
8277

8378
// Iterate until all positions are classified (30 cycles needed)
84-
do {
85-
repeat = false;
86-
87-
for (int i = 0; i < IndexMax; i++)
88-
if (bb[i] == RESULT_UNKNOWN)
89-
{
90-
pos.from_index(i);
91-
92-
bb[i] = (pos.sideToMove == WHITE) ? classify_wtm(pos, bb)
93-
: classify_btm(pos, bb);
94-
if (bb[i] != RESULT_UNKNOWN)
95-
repeat = true;
96-
}
97-
98-
} while (repeat);
79+
while (repeat)
80+
for (repeat = index = 0; index < IndexMax; index++)
81+
if ( db[index] == RESULT_UNKNOWN
82+
&& pos.classify(index, db) != RESULT_UNKNOWN)
83+
repeat = 1;
9984

10085
// Map 32 position results into one KPKBitbase[] entry
101-
for (int i = 0; i < IndexMax / 32; i++)
102-
for (int j = 0; j < 32; j++)
103-
if (bb[32 * i + j] == RESULT_WIN || bb[32 * i + j] == RESULT_LOSS)
104-
KPKBitbase[i] |= (1 << j);
86+
for (index = 0; index < IndexMax / 32; index++)
87+
for (bit = 0; bit < 32; bit++)
88+
if (db[32 * index + bit] == RESULT_WIN)
89+
KPKBitbase[index] |= (1 << bit);
10590
}
10691

10792

10893
namespace {
10994

110-
// A KPK bitbase index is an integer in [0, IndexMax] range
111-
//
112-
// Information is mapped in this way
113-
//
114-
// bit 0: side to move (WHITE or BLACK)
115-
// bit 1- 6: black king square (from SQ_A1 to SQ_H8)
116-
// bit 7-12: white king square (from SQ_A1 to SQ_H8)
117-
// bit 13-14: white pawn file (from FILE_A to FILE_D)
118-
// bit 15-17: white pawn rank - 1 (from RANK_2 - 1 to RANK_7 - 1)
95+
// A KPK bitbase index is an integer in [0, IndexMax] range
96+
//
97+
// Information is mapped in this way
98+
//
99+
// bit 0: side to move (WHITE or BLACK)
100+
// bit 1- 6: black king square (from SQ_A1 to SQ_H8)
101+
// bit 7-12: white king square (from SQ_A1 to SQ_H8)
102+
// bit 13-14: white pawn file (from FILE_A to FILE_D)
103+
// bit 15-17: white pawn rank - 1 (from RANK_2 - 1 to RANK_7 - 1)
119104

120105
int compute_index(Square wksq, Square bksq, Square wpsq, Color stm) {
121106

122107
assert(square_file(wpsq) <= FILE_D);
123108

124-
int p = int(square_file(wpsq)) + 4 * int(square_rank(wpsq) - 1);
125-
int r = int(stm) + 2 * int(bksq) + 128 * int(wksq) + 8192 * p;
109+
int p = square_file(wpsq) + 4 * (square_rank(wpsq) - 1);
110+
int r = stm + 2 * bksq + 128 * wksq + 8192 * p;
126111

127112
assert(r >= 0 && r < IndexMax);
128113

@@ -131,73 +116,79 @@ namespace {
131116

132117
void KPKPosition::from_index(int index) {
133118

134-
int s = (index / 8192) % 24;
135-
136-
sideToMove = Color(index % 2);
137-
blackKingSquare = Square((index / 2) % 64);
138-
whiteKingSquare = Square((index / 128) % 64);
139-
pawnSquare = make_square(File(s % 4), Rank(s / 4 + 1));
119+
int s = index >> 13;
120+
sideToMove = Color(index & 1);
121+
blackKingSquare = Square((index >> 1) & 63);
122+
whiteKingSquare = Square((index >> 7) & 63);
123+
pawnSquare = make_square(File(s & 3), Rank((s >> 2) + 1));
140124
}
141125

142-
bool KPKPosition::is_legal() const {
126+
Result KPKPosition::classify_knowns(int index) {
143127

128+
from_index(index);
129+
130+
// Check if two pieces are on the same square
144131
if ( whiteKingSquare == pawnSquare
145132
|| whiteKingSquare == blackKingSquare
146133
|| blackKingSquare == pawnSquare)
147-
return false;
148-
149-
if (sideToMove == WHITE)
150-
{
151-
if ( bit_is_set(wk_attacks(), blackKingSquare)
152-
|| bit_is_set(pawn_attacks(), blackKingSquare))
153-
return false;
154-
}
155-
else if (bit_is_set(bk_attacks(), whiteKingSquare))
156-
return false;
157-
158-
return true;
159-
}
134+
return RESULT_INVALID;
160135

161-
bool KPKPosition::is_immediate_draw() const {
136+
// Check if a king can be captured
137+
if ( bit_is_set(wk_attacks(), blackKingSquare)
138+
|| (bit_is_set(pawn_attacks(), blackKingSquare) && sideToMove == WHITE))
139+
return RESULT_INVALID;
162140

163-
if (sideToMove == BLACK)
164-
{
165-
Bitboard wka = wk_attacks();
166-
Bitboard bka = bk_attacks();
167-
168-
// Case 1: Stalemate
169-
if ((bka & ~(wka | pawn_attacks())) == EmptyBoardBB)
170-
return true;
171-
172-
// Case 2: King can capture pawn
173-
if (bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
174-
return true;
175-
}
176-
else
177-
{
178-
// Case 1: Stalemate (possible pawn files are only from A to D)
179-
if ( whiteKingSquare == SQ_A8
180-
&& pawnSquare == SQ_A7
181-
&& (blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
182-
return true;
183-
}
184-
return false;
141+
// The position is an immediate win if it is white to move and the
142+
// white pawn can be promoted without getting captured.
143+
if ( square_rank(pawnSquare) == RANK_7
144+
&& sideToMove == WHITE
145+
&& whiteKingSquare != pawnSquare + DELTA_N
146+
&& ( square_distance(blackKingSquare, pawnSquare + DELTA_N) > 1
147+
|| bit_is_set(wk_attacks(), pawnSquare + DELTA_N)))
148+
return RESULT_WIN;
149+
150+
// Check for known draw positions
151+
//
152+
// Case 1: Stalemate
153+
if ( sideToMove == BLACK
154+
&& (bk_attacks() & ~(wk_attacks() | pawn_attacks())) == EmptyBoardBB)
155+
return RESULT_DRAW;
156+
157+
// Case 2: King can capture pawn
158+
if ( sideToMove == BLACK
159+
&& bit_is_set(bk_attacks(), pawnSquare) && !bit_is_set(wk_attacks(), pawnSquare))
160+
return RESULT_DRAW;
161+
162+
// Case 3: Black king in front of white pawn
163+
if ( blackKingSquare == pawnSquare + DELTA_N
164+
&& square_rank(pawnSquare) < RANK_7)
165+
return RESULT_DRAW;
166+
167+
// Case 4: White king in front of pawn and black has opposition
168+
if ( whiteKingSquare == pawnSquare + DELTA_N
169+
&& blackKingSquare == pawnSquare + DELTA_N + DELTA_N + DELTA_N
170+
&& square_rank(pawnSquare) < RANK_5
171+
&& sideToMove == WHITE)
172+
return RESULT_DRAW;
173+
174+
// Case 5: Stalemate with rook pawn
175+
if ( blackKingSquare == SQ_A8
176+
&& square_file(pawnSquare) == FILE_A)
177+
return RESULT_DRAW;
178+
179+
return RESULT_UNKNOWN;
185180
}
186181

187-
bool KPKPosition::is_immediate_win() const {
182+
Result KPKPosition::classify(int index, Result db[]) {
188183

189-
// The position is an immediate win if it is white to move and the
190-
// white pawn can be promoted without getting captured.
191-
return sideToMove == WHITE
192-
&& square_rank(pawnSquare) == RANK_7
193-
&& whiteKingSquare != pawnSquare + DELTA_N
194-
&& ( square_distance(blackKingSquare, pawnSquare + DELTA_N) > 1
195-
|| bit_is_set(wk_attacks(), pawnSquare + DELTA_N));
184+
from_index(index);
185+
db[index] = (sideToMove == WHITE ? classify_white(db) : classify_black(db));
186+
return db[index];
196187
}
197188

198-
Result classify_wtm(const KPKPosition& pos, const Result bb[]) {
189+
Result KPKPosition::classify_white(const Result db[]) {
199190

200-
// If one move leads to a position classified as RESULT_LOSS, the result
191+
// If one move leads to a position classified as RESULT_WIN, the result
201192
// of the current position is RESULT_WIN. If all moves lead to positions
202193
// classified as RESULT_DRAW, the current position is classified RESULT_DRAW
203194
// otherwise the current position is classified as RESULT_UNKNOWN.
@@ -208,40 +199,38 @@ namespace {
208199
Result r;
209200

210201
// King moves
211-
b = pos.wk_attacks();
202+
b = wk_attacks();
212203
while (b)
213204
{
214205
s = pop_1st_bit(&b);
215-
r = bb[compute_index(s, pos.blackKingSquare, pos.pawnSquare, BLACK)];
206+
r = db[compute_index(s, blackKingSquare, pawnSquare, BLACK)];
216207

217-
if (r == RESULT_LOSS)
208+
if (r == RESULT_WIN)
218209
return RESULT_WIN;
219210

220211
if (r == RESULT_UNKNOWN)
221212
unknownFound = true;
222213
}
223214

224215
// Pawn moves
225-
if (square_rank(pos.pawnSquare) < RANK_7)
216+
if (square_rank(pawnSquare) < RANK_7)
226217
{
227-
s = pos.pawnSquare + DELTA_N;
228-
r = bb[compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK)];
218+
s = pawnSquare + DELTA_N;
219+
r = db[compute_index(whiteKingSquare, blackKingSquare, s, BLACK)];
229220

230-
if (r == RESULT_LOSS)
221+
if (r == RESULT_WIN)
231222
return RESULT_WIN;
232223

233224
if (r == RESULT_UNKNOWN)
234225
unknownFound = true;
235226

236227
// Double pawn push
237-
if ( square_rank(s) == RANK_3
238-
&& s != pos.whiteKingSquare
239-
&& s != pos.blackKingSquare)
228+
if (square_rank(s) == RANK_3 && r != RESULT_INVALID)
240229
{
241230
s += DELTA_N;
242-
r = bb[compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK)];
231+
r = db[compute_index(whiteKingSquare, blackKingSquare, s, BLACK)];
243232

244-
if (r == RESULT_LOSS)
233+
if (r == RESULT_WIN)
245234
return RESULT_WIN;
246235

247236
if (r == RESULT_UNKNOWN)
@@ -251,34 +240,32 @@ namespace {
251240
return unknownFound ? RESULT_UNKNOWN : RESULT_DRAW;
252241
}
253242

254-
255-
Result classify_btm(const KPKPosition& pos, const Result bb[]) {
243+
Result KPKPosition::classify_black(const Result db[]) {
256244

257245
// If one move leads to a position classified as RESULT_DRAW, the result
258246
// of the current position is RESULT_DRAW. If all moves lead to positions
259-
// classified as RESULT_WIN, the current position is classified as
260-
// RESULT_LOSS. Otherwise, the current position is classified as
261-
// RESULT_UNKNOWN.
247+
// classified as RESULT_WIN, the position is classified as RESULT_WIN.
248+
// Otherwise, the current position is classified as RESULT_UNKNOWN.
262249

263250
bool unknownFound = false;
264251
Bitboard b;
265252
Square s;
266253
Result r;
267254

268255
// King moves
269-
b = pos.bk_attacks();
256+
b = bk_attacks();
270257
while (b)
271258
{
272259
s = pop_1st_bit(&b);
273-
r = bb[compute_index(pos.whiteKingSquare, s, pos.pawnSquare, WHITE)];
260+
r = db[compute_index(whiteKingSquare, s, pawnSquare, WHITE)];
274261

275262
if (r == RESULT_DRAW)
276263
return RESULT_DRAW;
277264

278265
if (r == RESULT_UNKNOWN)
279266
unknownFound = true;
280267
}
281-
return unknownFound ? RESULT_UNKNOWN : RESULT_LOSS;
268+
return unknownFound ? RESULT_UNKNOWN : RESULT_WIN;
282269
}
283270

284271
}

src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ using namespace std;
3939

4040
extern bool execute_uci_command(const string& cmd);
4141
extern void benchmark(int argc, char* argv[]);
42-
extern void init_kpk_bitbase();
42+
extern void kpk_bitbase_init();
4343

4444
int main(int argc, char* argv[]) {
4545

@@ -52,7 +52,7 @@ int main(int argc, char* argv[]) {
5252
// Startup initializations
5353
init_bitboards();
5454
Position::init();
55-
init_kpk_bitbase();
55+
kpk_bitbase_init();
5656
init_search();
5757
Threads.init();
5858

0 commit comments

Comments
 (0)