@@ -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
10893namespace {
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}
0 commit comments