1 #if defined(DEBUG)
2 # include "chess.h"
3 # include "data.h"
4 /* last modified 02/26/14 */
5 /*
6 *******************************************************************************
7 * *
8 * ValidatePosition() is a debugging tool that is enabled by using the *
9 * -DDEBUG compilation flag. This procedure tests the various data *
10 * structures used in Crafty related to the chess board and incrementally *
11 * updated values like hash signatures and so forth. It simply looks for *
12 * consistency between the various bitboards, and recomputes the hash *
13 * signatures to determine if they are correct. If anything fails to pass *
14 * the validation test, we print out a dump of the moves made in this path *
15 * through the tree, and then exit since things are corrupted. *
16 * *
17 * This greatly slows the program down, because ValidatePosition() is called *
18 * after each Make()/Unmake() (these are the functions that modify the *
19 * primary data structures). In general, this will not be used by users *
20 * unless they are modifying the source code themselves. *
21 * *
22 *******************************************************************************
23 */
ValidatePosition(TREE * RESTRICT tree,int ply,int move,char * caller)24 void ValidatePosition(TREE * RESTRICT tree, int ply, int move, char *caller) {
25 uint64_t temp, temp1, temp_occ;
26 uint64_t temp_occx;
27 int i, square, error = 0;
28 int side, piece, temp_score;
29
30 /*
31 ************************************************************
32 * *
33 * First, test occupied[side] which should match the OR *
34 * result of all pieces[side]. *
35 * *
36 ************************************************************
37 */
38 for (side = black; side <= white; side++) {
39 temp_occ =
40 Pawns(side) | Knights(side) | Bishops(side) | Rooks(side) |
41 Queens(side)
42 | Kings(side);
43 if (Occupied(side) ^ temp_occ) {
44 if (!error)
45 Print(2048, "\n");
46 Print(2048, "ERROR %s occupied squares is bad!\n",
47 (side) ? "white" : "black");
48 Display2BitBoards(temp_occ, Occupied(white));
49 error = 1;
50 }
51 }
52 /*
53 ************************************************************
54 * *
55 * Now we do some sanity tests on the actual chess board *
56 * information. The first test is to make sure that no *
57 * bitmap square is set in more than one bitmap, which *
58 * would imply two different pieces on the same square. *
59 * *
60 ************************************************************
61 */
62 temp_occ =
63 Pawns(white) ^ Knights(white) ^ Bishops(white) ^ Rooks(white) ^
64 Queens(white) ^ Pawns(black) ^ Knights(black) ^ Bishops(black) ^
65 Rooks(black) ^ Queens(black) ^ Kings(white) ^ Kings(black);
66 temp_occx =
67 Pawns(white) | Knights(white) | Bishops(white) | Rooks(white) |
68 Queens(white) | Pawns(black) | Knights(black) | Bishops(black) |
69 Rooks(black) | Queens(black) | Kings(white) | Kings(black);
70 if (temp_occ ^ temp_occx) {
71 if (!error)
72 Print(2048, "\n");
73 Print(2048, "ERROR two pieces on same square\n");
74 error = 1;
75 }
76 /*
77 ************************************************************
78 * *
79 * Add up all the pieces (material values) to see if this *
80 * matches the incrementally updated value. *
81 * *
82 ************************************************************
83 */
84 temp_score = 0;
85 for (side = black; side <= white; side++)
86 for (piece = pawn; piece < king; piece++)
87 temp_score += PopCnt(Pieces(side, piece)) * PieceValues(side, piece);
88 if (temp_score != Material) {
89 if (!error)
90 Print(2048, "\n");
91 Print(2048, "ERROR material evaluation is wrong, good=%d, bad=%d\n",
92 temp_score, Material);
93 error = 1;
94 }
95 /*
96 ************************************************************
97 * *
98 * Next, check the incrementally updated piece counts for *
99 * both sides. ditto for pawn counts. *
100 * *
101 ************************************************************
102 */
103 for (side = black; side <= white; side++) {
104 temp_score = 0;
105 for (piece = knight; piece < king; piece++)
106 temp_score += PopCnt(Pieces(side, piece)) * p_vals[piece];
107 if (temp_score != TotalPieces(side, occupied)) {
108 if (!error)
109 Print(2048, "\n");
110 Print(2048, "ERROR %s pieces is wrong, good=%d, bad=%d\n",
111 (side) ? "white" : "black", temp_score, TotalPieces(side,
112 occupied));
113 error = 1;
114 }
115 }
116 for (side = black; side <= white; side++) {
117 temp_score = PopCnt(Pawns(side));
118 if (temp_score != TotalPieces(side, pawn)) {
119 if (!error)
120 Print(2048, "\n");
121 Print(2048, "ERROR %s pawns is wrong, good=%d, bad=%d\n",
122 (side) ? "white" : "black", temp_score, TotalPieces(side, pawn));
123 error = 1;
124 }
125 }
126 i = PopCnt(OccupiedSquares);
127 if (i != TotalAllPieces) {
128 if (!error)
129 Print(2048, "\n");
130 Print(2048, "ERROR! TotalAllPieces is wrong, correct=%d bad=%d\n", i,
131 TotalAllPieces);
132 error = 1;
133 }
134 /*
135 ************************************************************
136 * *
137 * Now we cycle through each different chessboard bitmap *
138 * and verify that each piece in a bitmap matches the same *
139 * piece type in the board[64] array. *
140 * *
141 ************************************************************
142 */
143 for (side = black; side <= white; side++)
144 for (piece = pawn; piece <= king; piece++) {
145 temp = Pieces(side, piece);
146 while (temp) {
147 square = LSB(temp);
148 if (PcOnSq(square) != pieces[side][piece]) {
149 if (!error)
150 Print(2048, "\n");
151 Print(2048, "ERROR! board[%d]=%d, should be %d\n", square,
152 PcOnSq(square), pieces[side][piece]);
153 error = 1;
154 }
155 temp &= temp - 1;
156 }
157 }
158 /*
159 ************************************************************
160 * *
161 * And then we look at the board[64] array and make sure *
162 * that any non-zero piece matches the proper bitmap for *
163 * that particular piece type. *
164 * *
165 ************************************************************
166 */
167 for (i = 0; i < 64; i++) {
168 if (!PcOnSq(i))
169 continue;
170 side = (PcOnSq(i) > 0) ? 1 : 0;
171 if (SetMask(i) & Pieces(side, Abs(PcOnSq(i))))
172 continue;
173 if (!error)
174 Print(2048, "\n");
175 Print(2048, "ERROR! bitboards/board[%d] don't agree!\n", i);
176 error = 1;
177 break;
178 }
179 /*
180 ************************************************************
181 * *
182 * The last chess board test is to make sure that any *
183 * square that is empty according to board[64] is also *
184 * empty according to the occupied squares bitmap. *
185 * *
186 ************************************************************
187 */
188 temp = ~(temp_occ | temp_occx);
189 while (temp) {
190 square = LSB(temp);
191 if (PcOnSq(square)) {
192 if (!error)
193 Print(2048, "\n");
194 Print(2048, "ERROR! board[%d]=%d, should be 0\n", square,
195 PcOnSq(square));
196 error = 1;
197 }
198 temp &= temp - 1;
199 }
200 /*
201 ************************************************************
202 * *
203 * Finally, we re-compute the pawn hash signature and the *
204 * normal hash signature and verify that they match the *
205 * incrementally updated values. *
206 * *
207 ************************************************************
208 */
209 temp = 0;
210 temp1 = 0;
211 for (i = 0; i < 64; i++) {
212 side = (PcOnSq(i) > 0) ? 1 : 0;
213 temp ^= randoms[side][Abs(PcOnSq(i))][i];
214 if (Abs(PcOnSq(i)) == pawn)
215 temp1 ^= randoms[side][Abs(PcOnSq(i))][i];
216 }
217 if (EnPassant(ply))
218 temp ^= enpassant_random[EnPassant(ply)];
219 for (side = black; side <= white; side++) {
220 if (Castle(ply, side) < 0 || !(Castle(ply, side) & 1))
221 temp ^= castle_random[0][side];
222 if (Castle(ply, side) < 0 || !(Castle(ply, side) & 2))
223 temp ^= castle_random[1][side];
224 }
225 if (temp ^ HashKey) {
226 if (!error)
227 Print(2048, "\n");
228 Print(2048, "ERROR! hash_key is bad.\n");
229 error = 1;
230 }
231 if (temp1 ^ PawnHashKey) {
232 if (!error)
233 Print(2048, "\n");
234 Print(2048, "ERROR! pawn_hash_key is bad.\n");
235 error = 1;
236 }
237 /*
238 ************************************************************
239 * *
240 * If any inconsistencies/errors were found, we are going *
241 * to dump as much debugging information as possible to *
242 * help pinpoint the source of the problem. *
243 * *
244 ************************************************************
245 */
246 if (error) {
247 Lock(lock_smp);
248 Unlock(lock_smp);
249 Print(2048, "ply=%d\n", tree->ply);
250 Print(2048, "phase[%d]=%d current move:\n", ply, tree->phase[ply]);
251 DisplayChessMove("move=", move);
252 DisplayChessBoard(stdout, tree->position);
253 Print(2048, "called from %s, ply=%d\n", caller, ply);
254 Print(2048, "node=%" PRIu64 "\n", tree->nodes_searched);
255 Print(2048, "active path:\n");
256 for (i = 1; i <= ply; i++) {
257 Print(2048, "ply=%d ", i);
258 DisplayChessMove("move=", tree->curmv[i]);
259 }
260 CraftyExit(1);
261 }
262 }
263 #endif
264