2 Glaurung, a UCI chess playing engine.
3 Copyright (C) 2004-2008 Tord Romstad
5 Glaurung is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 Glaurung is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 //// Local definitions
47 void from_index(int index
);
49 bool is_legal() const;
50 bool is_immediate_draw() const;
51 bool is_immediate_win() const;
52 Bitboard
wk_attacks() const;
53 Bitboard
bk_attacks() const;
54 Bitboard
pawn_attacks() const;
56 Square whiteKingSquare
, blackKingSquare
, pawnSquare
;
62 const int IndexMax
= 2*24*64*64;
66 bool next_iteration();
67 Result
classify_wtm(const KPKPosition
&p
);
68 Result
classify_btm(const KPKPosition
&p
);
69 int compute_index(Square wksq
, Square bksq
, Square psq
, Color stm
);
70 int compress_result(Result r
);
79 void generate_kpk_bitbase(uint8_t bitbase
[]) {
80 // Allocate array and initialize:
81 Bitbase
= new Result
[IndexMax
];
84 // Iterate until all positions are classified:
85 while(next_iteration());
87 // Compress bitbase into the supplied parameter:
89 for(i
= 0; i
< 24576; i
++) {
90 for(b
= 0, j
= 0; j
< 8; b
|= (compress_result(Bitbase
[8*i
+j
]) << j
), j
++);
94 // Release allocated memory:
101 void KPKPosition::from_index(int index
) {
103 sideToMove
= Color(index
% 2);
104 blackKingSquare
= Square((index
/ 2) % 64);
105 whiteKingSquare
= Square((index
/ 128) % 64);
106 s
= (index
/ 8192) % 24;
107 pawnSquare
= make_square(File(s
% 4), Rank(s
/ 4 + 1));
111 int KPKPosition::to_index() const {
112 return compute_index(whiteKingSquare
, blackKingSquare
, pawnSquare
,
117 bool KPKPosition::is_legal() const {
118 if(whiteKingSquare
== pawnSquare
|| whiteKingSquare
== blackKingSquare
||
119 pawnSquare
== blackKingSquare
)
121 if(sideToMove
== WHITE
) {
122 if(bit_is_set(this->wk_attacks(), blackKingSquare
))
124 if(bit_is_set(this->pawn_attacks(), blackKingSquare
))
128 if(bit_is_set(this->bk_attacks(), whiteKingSquare
))
135 bool KPKPosition::is_immediate_draw() const {
136 if(sideToMove
== BLACK
) {
137 Bitboard wka
= this->wk_attacks();
138 Bitboard bka
= this->bk_attacks();
141 if((bka
& ~(wka
| this->pawn_attacks())) == EmptyBoardBB
)
144 // Case 2: King can capture pawn
145 if(bit_is_set(bka
, pawnSquare
) && !bit_is_set(wka
, pawnSquare
))
150 if(whiteKingSquare
== SQ_A8
&& pawnSquare
== SQ_A7
&&
151 (blackKingSquare
== SQ_C7
|| blackKingSquare
== SQ_C8
))
159 bool KPKPosition::is_immediate_win() const {
160 // The position is an immediate win if it is white to move and the white
161 // pawn can be promoted without getting captured:
163 sideToMove
== WHITE
&&
164 square_rank(pawnSquare
) == RANK_7
&&
165 (square_distance(blackKingSquare
, pawnSquare
+DELTA_N
) > 1 ||
166 bit_is_set(this->wk_attacks(), pawnSquare
+DELTA_N
));
170 Bitboard
KPKPosition::wk_attacks() const {
171 return StepAttackBB
[WK
][whiteKingSquare
];
175 Bitboard
KPKPosition::bk_attacks() const {
176 return StepAttackBB
[BK
][blackKingSquare
];
180 Bitboard
KPKPosition::pawn_attacks() const {
181 return StepAttackBB
[WP
][pawnSquare
];
187 for(int i
= 0; i
< IndexMax
; i
++) {
190 Bitbase
[i
] = RESULT_INVALID
;
191 else if(p
.is_immediate_draw())
192 Bitbase
[i
] = RESULT_DRAW
;
193 else if(p
.is_immediate_win())
194 Bitbase
[i
] = RESULT_WIN
;
196 Bitbase
[i
] = RESULT_UNKNOWN
;
203 bool next_iteration() {
205 int previousUnknownCount
= UnknownCount
;
207 for(int i
= 0; i
< IndexMax
; i
++)
208 if(Bitbase
[i
] == RESULT_UNKNOWN
) {
211 Bitbase
[i
] = (p
.sideToMove
== WHITE
)? classify_wtm(p
) : classify_btm(p
);
213 if(Bitbase
[i
] == RESULT_WIN
|| Bitbase
[i
] == RESULT_LOSS
||
214 Bitbase
[i
] == RESULT_DRAW
)
218 return UnknownCount
!= previousUnknownCount
;
222 Result
classify_wtm(const KPKPosition
&p
) {
224 // If one move leads to a position classified as RESULT_LOSS, the result
225 // of the current position is RESULT_WIN. If all moves lead to positions
226 // classified as RESULT_DRAW, the current position is classified as
227 // RESULT_DRAW. Otherwise, the current position is classified as
230 bool unknownFound
= false;
238 switch(Bitbase
[compute_index(s
, p
.blackKingSquare
, p
.pawnSquare
,
247 case RESULT_DRAW
: case RESULT_INVALID
:
256 if(square_rank(p
.pawnSquare
) < RANK_7
) {
257 s
= p
.pawnSquare
+ DELTA_N
;
258 switch(Bitbase
[compute_index(p
.whiteKingSquare
, p
.blackKingSquare
, s
,
267 case RESULT_DRAW
: case RESULT_INVALID
:
274 if(square_rank(s
) == RANK_3
&&
275 s
!= p
.whiteKingSquare
&& s
!= p
.blackKingSquare
) {
277 switch(Bitbase
[compute_index(p
.whiteKingSquare
, p
.blackKingSquare
, s
,
286 case RESULT_DRAW
: case RESULT_INVALID
:
295 return unknownFound
? RESULT_UNKNOWN
: RESULT_DRAW
;
299 Result
classify_btm(const KPKPosition
&p
) {
301 // If one move leads to a position classified as RESULT_DRAW, the result
302 // of the current position is RESULT_DRAW. If all moves lead to positions
303 // classified as RESULT_WIN, the current position is classified as
304 // RESULT_LOSS. Otherwise, the current position is classified as
307 bool unknownFound
= false;
315 switch(Bitbase
[compute_index(p
.whiteKingSquare
, s
, p
.pawnSquare
,
324 case RESULT_WIN
: case RESULT_INVALID
:
332 return unknownFound
? RESULT_UNKNOWN
: RESULT_LOSS
;
336 int compute_index(Square wksq
, Square bksq
, Square psq
, Color stm
) {
337 int p
= int(square_file(psq
)) + (int(square_rank(psq
)) - 1) * 4;
338 int result
= int(stm
) + 2*int(bksq
) + 128*int(wksq
) + 8192*p
;
339 assert(result
>= 0 && result
< IndexMax
);
344 int compress_result(Result r
) {
345 return (r
== RESULT_WIN
|| r
== RESULT_LOSS
)? 1 : 0;