Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 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
 */
24
void ValidatePosition(TREE * RESTRICT tree, int ply, int move, char *caller) {
25
  uint64_t temp, temp1, temp_occ;
26
  uint64_t temp_occx;
108 pmbaty 27
  int i, square, error = 0;
33 pmbaty 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) {
108 pmbaty 44
      if (!error)
45
        Print(2048, "\n");
46
      Print(2048, "ERROR %s occupied squares is bad!\n",
33 pmbaty 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) {
108 pmbaty 71
    if (!error)
72
      Print(2048, "\n");
73
    Print(2048, "ERROR two pieces on same square\n");
33 pmbaty 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) {
108 pmbaty 89
    if (!error)
90
      Print(2048, "\n");
91
    Print(2048, "ERROR  material evaluation is wrong, good=%d, bad=%d\n",
33 pmbaty 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 pmbaty 108
      if (!error)
109
        Print(2048, "\n");
110
      Print(2048, "ERROR  %s pieces is wrong, good=%d, bad=%d\n",
33 pmbaty 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)) {
108 pmbaty 119
      if (!error)
120
        Print(2048, "\n");
121
      Print(2048, "ERROR  %s pawns is wrong, good=%d, bad=%d\n",
33 pmbaty 122
          (side) ? "white" : "black", temp_score, TotalPieces(side, pawn));
123
      error = 1;
124
    }
125
  }
126
  i = PopCnt(OccupiedSquares);
127
  if (i != TotalAllPieces) {
108 pmbaty 128
    if (!error)
129
      Print(2048, "\n");
130
    Print(2048, "ERROR!  TotalAllPieces is wrong, correct=%d  bad=%d\n", i,
33 pmbaty 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]) {
108 pmbaty 149
          if (!error)
150
            Print(2048, "\n");
151
          Print(2048, "ERROR!  board[%d]=%d, should be %d\n", square,
33 pmbaty 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;
108 pmbaty 173
    if (!error)
174
      Print(2048, "\n");
175
    Print(2048, "ERROR!  bitboards/board[%d] don't agree!\n", i);
33 pmbaty 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)) {
108 pmbaty 192
      if (!error)
193
        Print(2048, "\n");
194
      Print(2048, "ERROR!  board[%d]=%d, should be 0\n", square,
33 pmbaty 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) {
108 pmbaty 226
    if (!error)
227
      Print(2048, "\n");
228
    Print(2048, "ERROR!  hash_key is bad.\n");
33 pmbaty 229
    error = 1;
230
  }
231
  if (temp1 ^ PawnHashKey) {
108 pmbaty 232
    if (!error)
233
      Print(2048, "\n");
234
    Print(2048, "ERROR!  pawn_hash_key is bad.\n");
33 pmbaty 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) {
108 pmbaty 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]);
33 pmbaty 251
    DisplayChessMove("move=", move);
252
    DisplayChessBoard(stdout, tree->position);
108 pmbaty 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);
33 pmbaty 258
      DisplayChessMove("move=", tree->curmv[i]);
108 pmbaty 259
    }
33 pmbaty 260
    CraftyExit(1);
261
  }
262
}
263
#endif