Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pmbaty 1
#include "chess.h"
2
#include "data.h"
3
/* last modified 02/26/14 */
4
/*
5
 *******************************************************************************
6
 *                                                                             *
7
 *   Test() is used to test the program against a suite of test positions to   *
8
 *   measure its performance on a particular machine, or to evaluate its skill *
9
 *   after modifying it in some way.                                           *
10
 *                                                                             *
11
 *   The test is initiated by using the "test <filename>" command to read in   *
12
 *   the suite of problems from file <filename>.  The format of this file is   *
13
 *   as follows:                                                               *
14
 *                                                                             *
15
 *   Setboard <forsythe-string>:  This sets the board position using the usual *
16
 *   forsythe notation (see module SetBoard() in setc for a full ex-           *
17
 *   planation of the syntax).                                                 *
18
 *                                                                             *
19
 *   Solution <move1> <move2> ... <moven>:  this provides a solution move (or  *
20
 *   set of solution moves if more than one is correct).  If the search finds  *
21
 *   one of these moves, then the prblem is counted as correct, otherwise it   *
22
 *   is counted wrong.                                                         *
23
 *                                                                             *
24
 *   After reading these two lines, the program then searches to whatever time *
25
 *   or depth limit has been set, when it reaches the end-of-file condition or *
26
 *   when it reads a record containing the string "end" it then displays the   *
27
 *   number correct and the number missed.                                     *
28
 *                                                                             *
29
 *   There are two test modules here.  Test() handles the specific Crafty test *
30
 *   data format (dates back to Cray Blitz days) while TestEPD() handles the   *
31
 *   EPD-style test positions which is more concise.  Other than the parsing   *
32
 *   differences, these are identical modules.                                 *
33
 *                                                                             *
34
 *******************************************************************************
35
 */
36
void Test(char *filename) {
37
  FILE *test_input;
38
  int i, move, right = 0, wrong = 0, correct;
39
  int time = 0, len;
40
  uint64_t nodes = 0;
41
  char *eof, *delim;
42
  float avg_depth = 0.0;
43
  TREE *const tree = block[0];
44
 
45
/*
46
 ************************************************************
47
 *                                                          *
48
 *  Read in the position and then the solutions.  After     *
49
 *  executing a search to find the best move (according to  *
50
 *  the program, anyway) compare it against the list of     *
51
 *  solutions and count it right or wrong.                  *
52
 *                                                          *
53
 ************************************************************
54
 */
55
  fopen_s (&test_input, filename, "r");
56
  if (!test_input) {
57
    printf("file %s does not exist.\n", filename);
58
    return;
59
  }
60
  Print(4095, "\n");
61
  eof = fgets(buffer, 4096, test_input);
62
  if (strstr(buffer, "title"));
63
  else {
64
    fclose(test_input);
65
    TestEPD(filename);
66
    return;
67
  }
68
  if (book_file) {
69
    fclose(book_file);
70
    book_file = 0;
71
  }
72
  if (books_file) {
73
    fclose(books_file);
74
    books_file = 0;
75
  }
76
  while (1) {
77
    if (eof) {
78
      delim = strchr(buffer, '\n');
79
      if (delim)
80
        *delim = 0;
81
      delim = strchr(buffer, '\r');
82
      if (delim)
83
        *delim = ' ';
84
    } else
85
      break;
86
    nargs = ReadParse(buffer, args, " ;");
87
    if (!strcmp(args[0], "end"))
88
      break;
89
    else if (!strcmp(args[0], "title")) {
90
      Print(4095,
91
          "=============================================="
92
          "========================\n");
93
      Print(4095, "! ");
94
      len = 0;
95
      for (i = 1; i < nargs; i++) {
96
        Print(4095, "%s ", args[i]);
97
        len += strlen(args[i]) + 1;
98
        if (len > 65)
99
          break;
100
      }
101
      for (i = len; i < 67; i++)
102
        printf(" ");
103
      Print(4095, "!\n");
104
      Print(4095,
105
          "=============================================="
106
          "========================\n");
107
    } else if (strcmp(args[0], "solution")) {
108
      Option(tree);
109
    } else {
110
      number_of_solutions = 0;
111
      solution_type = 0;
112
      Print(4095, "solution ");
113
      for (i = 1; i < nargs; i++) {
114
        if (args[i][strlen(args[i]) - 1] == '?') {
115
          solution_type = 1;
116
          args[i][strlen(args[i]) - 1] = '\0';
117
        } else if (*(args + i)[strlen(args[i]) - 1] == '!') {
118
          solution_type = 0;
119
          args[i][strlen(args[i]) - 1] = '\0';
120
        }
121
        move = InputMove(tree, args[i], 0, game_wtm, 0, 0);
122
        if (move) {
123
          solutions[number_of_solutions] = move;
124
          Print(4095, "%d. %s", (number_of_solutions++) + 1, OutputMove(tree,
125
                  move, 0, game_wtm));
126
          if (solution_type == 1)
127
            Print(4095, "? ");
128
          else
129
            Print(4095, "  ");
130
        } else
131
          DisplayChessBoard(stdout, tree->position);
132
      }
133
      Print(4095, "\n");
134
      InitializeHashTables();
135
      last_pv.pathd = 0;
136
      thinking = 1;
137
      tree->status[1] = tree->status[0];
138
      (void) Iterate(game_wtm, think, 0);
139
      thinking = 0;
140
      nodes += tree->nodes_searched;
141
      avg_depth += (float) iteration_depth;
142
      time += (end_time - start_time);
143
      correct = solution_type;
144
      for (i = 0; i < number_of_solutions; i++) {
145
        if (!solution_type) {
146
          if (solutions[i] == tree->pv[1].path[1])
147
            correct = 1;
148
        } else if (solutions[i] == tree->pv[1].path[1])
149
          correct = 0;
150
      }
151
      if (correct) {
152
        right++;
153
        Print(4095, "----------------------> solution correct (%d/%d).\n",
154
            right, right + wrong);
155
      } else {
156
        wrong++;
157
        Print(4095, "----------------------> solution incorrect (%d/%d).\n",
158
            right, right + wrong);
159
      }
160
    }
161
    eof = fgets(buffer, 4096, test_input);
162
  }
163
/*
164
 ************************************************************
165
 *                                                          *
166
 *  Now print the results.                                  *
167
 *                                                          *
168
 ************************************************************
169
 */
170
  if (right + wrong) {
171
    Print(4095, "\n\n\n");
172
    Print(4095, "test results summary:\n\n");
173
    Print(4095, "total positions searched..........%12d\n", right + wrong);
174
    Print(4095, "number right......................%12d\n", right);
175
    Print(4095, "number wrong......................%12d\n", wrong);
176
    Print(4095, "percentage right..................%12d\n",
177
        right * 100 / (right + wrong));
178
    Print(4095, "percentage wrong..................%12d\n",
179
        wrong * 100 / (right + wrong));
180
    Print(4095, "total nodes searched..............%12" PRIu64 "\n", nodes);
181
    Print(4095, "average search depth..............%12.1f\n",
182
        avg_depth / (right + wrong));
183
    Print(4095, "nodes per second..................%12" PRIu64 "\n",
184
        nodes * 100 / Max(time, 1));
185
    Print(4095, "total time........................%12s\n",
186
        DisplayTime(time));
187
  }
188
  input_stream = stdin;
189
  early_exit = 99;
190
}
191
 
192
/* last modified 02/26/14 */
193
/*
194
 *******************************************************************************
195
 *                                                                             *
196
 *   TestEPD() is used to test the program against a suite of test positions   *
197
 *   to measure its performance on a particular machine, or to evaluate its    *
198
 *   skill after modifying it in some way.                                     *
199
 *                                                                             *
200
 *   The test is initiated by using the "test <filename>" command to read in   *
201
 *   the suite of problems from file <filename>.  The format of this file is   *
202
 *   as follows:                                                               *
203
 *                                                                             *
204
 *   <forsythe-string>  am/bm move1 move2 etc; title "xxx"                     *
205
 *                                                                             *
206
 *   Am means "avoid move" and bm means "best move".  Each test position may   *
207
 *   have multiple moves to avoid or that are best, but both am and bm may not *
208
 *   appear on one position.                                                   *
209
 *                                                                             *
210
 *   The title is just a comment that is given in the program output to make   *
211
 *   it easier to match output to specific positions.                          *
212
 *                                                                             *
213
 *******************************************************************************
214
 */
215
void TestEPD(char *filename) {
216
  FILE *test_input;
217
  int i, move, right = 0, wrong = 0, correct;
218
  int time = 0, len;
219
  uint64_t nodes = 0;
220
  char *eof, *mvs, *title;
221
  float avg_depth = 0.0;
222
  TREE *const tree = block[0];
223
 
224
/*
225
 ************************************************************
226
 *                                                          *
227
 *  Read in the position and then the solutions.  After     *
228
 *  executing a search to find the best move (according to  *
229
 *  the program, anyway) compare it against the list of     *
230
 *  solutions and count it right or wrong.                  *
231
 *                                                          *
232
 ************************************************************
233
 */
234
  fopen_s(&test_input, filename, "r"); // Pierre-Marie Baty -- use safe version
235
  if (!test_input) {
236
    printf("file %s does not exist.\n", filename);
237
    return;
238
  }
239
  if (book_file) {
240
    fclose(book_file);
241
    book_file = 0;
242
  }
243
  if (books_file) {
244
    fclose(books_file);
245
    books_file = 0;
246
  }
247
  while (1) {
248
    eof = fgets(buffer, 4096, test_input);
249
    if (eof) {
250
      char *delim;
251
 
252
      delim = strchr(buffer, '\n');
253
      if (delim)
254
        *delim = 0;
255
      delim = strchr(buffer, '\r');
256
      if (delim)
257
        *delim = ' ';
258
    } else
259
      break;
260
    mvs = strstr(buffer, " bm ");
261
    if (!mvs)
262
      mvs = strstr(buffer, " am ");
263
    if (!mvs)
264
      Print(4095, "Warning. am/bm field missing, input string follows\n%s\n",
265
          buffer);
266
    if (mvs)
267
      mvs++;
268
    title = strstr(buffer, "id");
269
    if (mvs)
270
      *(mvs - 1) = 0;
271
    if (title)
272
      *(title - 1) = 0;
273
    if (title) {
274
      title = strchr(title, '\"') + 1;
275
      if (title) {
276
        if (strchr(title, '\"')) {
277
          *strchr(title, '\"') = 0;
278
        }
279
      }
280
      Print(4095,
281
          "=============================================="
282
          "========================\n");
283
      Print(4095, "! ");
284
      Print(4095, "%s ", title);
285
      len = 66 - strlen(title);
286
      for (i = 0; i < len; i++)
287
        printf(" ");
288
      Print(4095, "!\n");
289
      Print(4095,
290
          "=============================================="
291
          "========================\n");
292
    }
293
    Option(tree);
294
    if (mvs) {
295
      nargs = ReadParse(mvs, args, " ;");
296
      number_of_solutions = 0;
297
      solution_type = 0;
298
      if (!strcmp(args[0], "am"))
299
        solution_type = 1;
300
      Print(4095, "solution ");
301
      for (i = 1; i < nargs; i++) {
302
        if (!strcmp(args[i], "c0"))
303
          break;
304
        move = InputMove(tree, args[i], 0, game_wtm, 0, 0);
305
        if (move) {
306
          solutions[number_of_solutions] = move;
307
          Print(4095, "%d. %s", (number_of_solutions++) + 1, OutputMove(tree,
308
                  move, 0, game_wtm));
309
          if (solution_type == 1)
310
            Print(4095, "? ");
311
          else
312
            Print(4095, "  ");
313
        } else
314
          DisplayChessBoard(stdout, tree->position);
315
      }
316
    }
317
    Print(4095, "\n");
318
    InitializeHashTables();
319
    last_pv.pathd = 0;
320
    thinking = 1;
321
    tree->status[1] = tree->status[0];
322
    (void) Iterate(game_wtm, think, 0);
323
    thinking = 0;
324
    nodes += tree->nodes_searched;
325
    avg_depth += (float) iteration_depth;
326
    time += (end_time - start_time);
327
    correct = solution_type;
328
    for (i = 0; i < number_of_solutions; i++) {
329
      if (!solution_type) {
330
        if (solutions[i] == tree->pv[1].path[1])
331
          correct = 1;
332
      } else if (solutions[i] == tree->pv[1].path[1])
333
        correct = 0;
334
    }
335
    if (correct) {
336
      right++;
337
      Print(4095, "----------------------> solution correct (%d/%d).\n",
338
          right, right + wrong);
339
    } else {
340
      wrong++;
341
      Print(4095, "----------------------> solution incorrect (%d/%d).\n",
342
          right, right + wrong);
343
    }
344
  }
345
/*
346
 ************************************************************
347
 *                                                          *
348
 *  Now print the results.                                  *
349
 *                                                          *
350
 ************************************************************
351
 */
352
  if (right + wrong) {
353
    Print(4095, "\n\n\n");
354
    Print(4095, "test results summary:\n\n");
355
    Print(4095, "total positions searched..........%12d\n", right + wrong);
356
    Print(4095, "number right......................%12d\n", right);
357
    Print(4095, "number wrong......................%12d\n", wrong);
358
    Print(4095, "percentage right..................%12d\n",
359
        right * 100 / (right + wrong));
360
    Print(4095, "percentage wrong..................%12d\n",
361
        wrong * 100 / (right + wrong));
362
    Print(4095, "total nodes searched..............%12" PRIu64 "\n", nodes);
363
    Print(4095, "average search depth..............%12.1f\n",
364
        avg_depth / (right + wrong));
365
    Print(4095, "nodes per second..................%12" PRIu64 "\n",
366
        nodes * 100 / Max(1, time));
367
    Print(4095, "total time........................%12s\n",
368
        DisplayTime(time));
369
  }
370
  input_stream = stdin;
371
  early_exit = 99;
372
}