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