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