1 /* epd.cpp
2
3 GNU Chess protocol adapter
4
5 Copyright (C) 2001-2011 Free Software Foundation, Inc.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 // epd.cpp
23
24 // includes
25
26 #include <cerrno>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cstring>
30
31 #include "board.h"
32 #include "engine.h"
33 #include "epd.h"
34 #include "fen.h"
35 #include "line.h"
36 #include "move.h"
37 #include "move_legal.h"
38 #include "option.h"
39 #include "parse.h"
40 #include "san.h"
41 #include "uci.h"
42 #include "util.h"
43
44 namespace adapter {
45
46 // constants
47
48 static const bool UseDebug = false;
49 static const bool UseTrace = false;
50
51 static const int StringSize = 4096;
52
53 // variables
54
55 static int MinDepth;
56 static int MaxDepth;
57
58 static double MaxTime;
59 static double MinTime;
60
61 static int DepthDelta;
62
63 static int FirstMove;
64 static int FirstDepth;
65 static int FirstSelDepth;
66 static int FirstScore;
67 static double FirstTime;
68 static sint64 FirstNodeNb;
69 static move_t FirstPV[LineSize];
70
71 static int LastMove;
72 static int LastDepth;
73 static int LastSelDepth;
74 static int LastScore;
75 static double LastTime;
76 static sint64 LastNodeNb;
77 static move_t LastPV[LineSize];
78
79 // prototypes
80
81 static void epd_test_file (const char file_name[]);
82
83 static bool is_solution (int move, const board_t * board, const char bm[], const char am[]);
84 static bool string_contain (const char string[], const char substring[]);
85
86 static bool engine_step ();
87
88 // functions
89
90 // epd_test()
91
epd_test(int argc,char * argv[])92 void epd_test(int argc, char * argv[]) {
93
94 int i;
95 const char * epd_file;
96
97 epd_file = NULL;
98 my_string_set(&epd_file,"wac.epd");
99
100 MinDepth = 8;
101 MaxDepth = 63;
102
103 MinTime = 1.0;
104 MaxTime = 5.0;
105
106 DepthDelta = 3;
107
108 for (i = 1; i < argc; i++) {
109
110 if (false) {
111
112 } else if (my_string_equal(argv[i],"epd-test")) {
113
114 // skip
115
116 } else if (my_string_equal(argv[i],"-epd")) {
117
118 i++;
119 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
120
121 my_string_set(&epd_file,argv[i]);
122
123 } else if (my_string_equal(argv[i],"-min-depth")) {
124
125 i++;
126 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
127
128 MinDepth = atoi(argv[i]);
129
130 } else if (my_string_equal(argv[i],"-max-depth")) {
131
132 i++;
133 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
134
135 MaxDepth = atoi(argv[i]);
136
137 } else if (my_string_equal(argv[i],"-min-time")) {
138
139 i++;
140 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
141
142 MinTime = atof(argv[i]);
143
144 } else if (my_string_equal(argv[i],"-max-time")) {
145
146 i++;
147 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
148
149 MaxTime = atof(argv[i]);
150
151 } else if (my_string_equal(argv[i],"-depth-delta")) {
152
153 i++;
154 if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
155
156 DepthDelta = atoi(argv[i]);
157
158 } else {
159
160 my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]);
161 }
162 }
163
164 epd_test_file(epd_file);
165 }
166
167 // epd_test_file()
168
epd_test_file(const char file_name[])169 static void epd_test_file(const char file_name[]) {
170
171 FILE * file;
172 int hit, tot;
173 char epd[StringSize];
174 char am[StringSize], bm[StringSize], id[StringSize];
175 board_t board[1];
176 char string[StringSize];
177 int move;
178 char pv_string[StringSize];
179 bool correct;
180 double depth_tot, time_tot, node_tot;
181
182 ASSERT(file_name!=NULL);
183
184 // init
185
186 file = fopen(file_name,"r");
187 if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno));
188
189 hit = 0;
190 tot = 0;
191
192 depth_tot = 0.0;
193 time_tot = 0.0;
194 node_tot = 0.0;
195
196 // loop
197
198 while (my_file_read_line(file,epd,StringSize)) {
199
200 if (UseTrace) printf("%s\n",epd);
201
202 if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,"");
203 if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,"");
204 if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,"");
205
206 if (my_string_empty(am) && my_string_empty(bm)) {
207 my_fatal("epd_test(): no am or bm field in EPD\n");
208 }
209
210 // init
211
212 uci_send_ucinewgame(Uci);
213 uci_send_isready_sync(Uci);
214
215 ASSERT(!Uci->searching);
216
217 // position
218
219 if (!board_from_fen(board,epd)) ASSERT(false);
220 if (!board_to_fen(board,string,StringSize)) ASSERT(false);
221
222 engine_send(Engine,"position fen %s",string);
223
224 // search
225
226 engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth);
227 // engine_send(Engine,"go infinite");
228
229 // engine data
230
231 board_copy(Uci->board,board);
232
233 uci_clear(Uci);
234 Uci->searching = true;
235 Uci->pending_nb++;
236
237 FirstMove = MoveNone;
238 FirstDepth = 0;
239 FirstSelDepth = 0;
240 FirstScore = 0;
241 FirstTime = 0.0;
242 FirstNodeNb = 0;
243 line_clear(FirstPV);
244
245 LastMove = MoveNone;
246 LastDepth = 0;
247 LastSelDepth = 0;
248 LastScore = 0;
249 LastTime = 0.0;
250 LastNodeNb = 0;
251 line_clear(LastPV);
252
253 // parse engine output
254
255 while (engine_step()) {
256
257 // stop search?
258
259 if (Uci->depth > MaxDepth
260 || Uci->time >= MaxTime
261 || (Uci->depth - FirstDepth >= DepthDelta
262 && Uci->depth > MinDepth
263 && Uci->time >= MinTime
264 && is_solution(FirstMove,board,bm,am))) {
265 engine_send(Engine,"stop");
266 }
267 }
268
269 move = FirstMove;
270 correct = is_solution(move,board,bm,am);
271
272 if (correct) hit++;
273 tot++;
274
275 if (correct) {
276 depth_tot += double(FirstDepth);
277 time_tot += FirstTime;
278 node_tot += double(FirstNodeNb);
279 }
280
281 printf("%s %d %4d %4d",id,correct,hit,tot);
282
283 if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(false);
284 printf(" - %2d %6.2f %9lld %+6.2f %s\n",FirstDepth,FirstTime,FirstNodeNb,double(LastScore)/100.0,pv_string);
285 }
286
287 printf("%d/%d",hit,tot);
288
289 if (hit != 0) {
290
291 depth_tot /= double(hit);
292 time_tot /= double(hit);
293 node_tot /= double(hit);
294
295 printf(" - %.1f %.2f %.0f",depth_tot,time_tot,node_tot);
296 }
297
298 printf("\n");
299
300 fclose(file);
301 }
302
303 // is_solution()
304
is_solution(int move,const board_t * board,const char bm[],const char am[])305 static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) {
306
307 char move_string[256];
308 bool correct;
309
310 ASSERT(move!=MoveNone);
311 ASSERT(bm!=NULL);
312 ASSERT(am!=NULL);
313
314 if (!move_is_legal(move,board)) {
315 board_disp(board);
316 move_disp(move,board);
317 printf("\n\n");
318 }
319
320 ASSERT(move_is_legal(move,board));
321
322 if (!move_to_san(move,board,move_string,256)) ASSERT(false);
323
324 correct = false;
325 if (!my_string_empty(bm)) {
326 correct = string_contain(bm,move_string);
327 } else if (!my_string_empty(am)) {
328 correct = !string_contain(am,move_string);
329 } else {
330 ASSERT(false);
331 }
332
333 return correct;
334 }
335
336 // epd_get_op()
337
epd_get_op(const char record[],const char opcode[],char string[],int size)338 bool epd_get_op(const char record[], const char opcode[], char string[], int size) {
339
340 char op[256];
341 int len;
342 const char *p_start, *p_end;
343
344 ASSERT(record!=NULL);
345 ASSERT(opcode!=NULL);
346 ASSERT(string!=NULL);
347 ASSERT(size>0);
348
349 // find the opcode
350
351 sprintf(op," %s ",opcode);
352
353 p_start = strstr(record,op);
354 if (p_start == NULL) return false;
355
356 // skip the opcode
357
358 p_start += strlen(op);
359
360 // find the end
361
362 p_end = strchr(p_start,';');
363 if (p_end == NULL) return false;
364
365 // calculate the length
366
367 len = p_end - p_start;
368 if (size < len+1) my_fatal("epd_get_op(): size < len+1\n");
369
370 strncpy(string,p_start,len);
371 string[len] = '\0';
372
373 return true;
374 }
375
376 // string_contain()
377
string_contain(const char string[],const char substring[])378 static bool string_contain(const char string[], const char substring[]) {
379
380 char new_string[StringSize], *p;
381
382 strcpy(new_string,string); // HACK
383
384 for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {
385 if (my_string_equal(p,substring)) return true;
386 }
387
388 return false;
389 }
390
391 // engine_step()
392
engine_step()393 static bool engine_step() {
394
395 char string[StringSize];
396 int event;
397
398 engine_get(Engine,string,StringSize);
399 event = uci_parse(Uci,string);
400
401 if ((event & EVENT_MOVE) != 0) {
402
403 return false;
404 }
405
406 if ((event & EVENT_PV) != 0) {
407
408 LastMove = Uci->best_pv[0];
409 LastDepth = Uci->best_depth;
410 LastSelDepth = Uci->best_sel_depth;
411 LastScore = Uci->best_score;
412 LastTime = Uci->time;
413 LastNodeNb = Uci->node_nb;
414 line_copy(LastPV,Uci->best_pv);
415
416 if (LastMove != FirstMove) {
417 FirstMove = LastMove;
418 FirstDepth = LastDepth;
419 FirstSelDepth = LastSelDepth;
420 FirstScore = LastScore;
421 FirstTime = LastTime;
422 FirstNodeNb = LastNodeNb;
423 line_copy(FirstPV,LastPV);
424 }
425 }
426
427 return true;
428 }
429
430 } // namespace adapter
431
432 // end of epd.cpp
433
434