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