per test
[rattatechess.git] / moveparse.cpp
blob83fbceee94b433b4b8112e4e18f1ad4490ab5f04
1 /***************************************************************************
2 moveparse.cpp - description
3 -------------------
4 begin : mer ott 30 2002
5 copyright : (C) 2002-2007 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "engine.h"
19 #include "utils.h"
20 #include <string.h>
22 void Engine::print_moves(Move* m, int num, bool nums, bool walk_ht)
24 int i,j;
25 if(board.color_to_move==BLACK &&nums)
26 output("%d. ...",board.num_moves+1);
28 for(i=0;i<num;i++)
30 if(m[i].as_int == 0)
31 break;
33 if(board.color_to_move==WHITE && nums)
34 printf(" %d.",board.num_moves+1);
35 output(" %s", board.move_to_alg(MoveStr().data(), m[i]) );
36 board.do_move(m[i], save_buf[save_buf_num++]);
39 if(walk_ht)
41 Move hash_mv[24];
42 for(j=0;j<24-i;j++)
44 HashEntry *h = probe_hash( board.hash );
45 if(!h || !h->best_mv || h->depth<0)
46 break;
48 /* don't follow the hash if there is draw for repetition :) */
49 if( check_draw() )
51 output( " <DRAW>" );
52 break;
55 hash_mv[j] = board.uncompress_move( h->best_mv );
57 /* verify that the move in the hash is a legal move */
58 Move tmp[255];
59 int num_tmp = board.find_moves(tmp);
60 bool ok = false;
61 for(int q=0;q<num_tmp;q++)
62 if(tmp[q] == hash_mv[j])
64 ok = true;
65 break;
68 if(!ok)
69 break;
71 if(j==0)
72 output(" |");
74 if(board.color_to_move==WHITE && nums)
75 output(" %d.",board.num_moves+1);
76 output( " %s", board.move_to_alg(MoveStr().data(), hash_mv[j]) );
77 board.do_move(hash_mv[j], save_buf[save_buf_num++]);
80 while(j--)
81 board.undo_move(hash_mv[j], save_buf[--save_buf_num]);
84 while(i--)
85 board.undo_move(m[i], save_buf[--save_buf_num]);
87 output("\n");
90 /* TODO: load correctly the pgn that start with a fen */
91 int Engine::load_pgn(FILE *f)
93 char buf[1024];
95 board.set_as_default();
96 mv_done_num = 0;
98 while(1)
100 if(!fgets(buf, 1024, f))
101 return 0;
102 if(buf[0]=='\n' || buf[0]=='\r' || buf[0]=='\t'
103 || buf[0]==' ' || buf[0]=='[' || buf[0]=='#')
104 continue;
105 break;
108 while(1)
110 char *ptr = buf;
111 ptr += strspn(ptr, ". \t\r\n");
113 for(int i=0;;i++)
115 if(!*ptr)
116 break;
117 char *t = ptr;
118 char *tmp = (ptr += strcspn(ptr, ". \t\r\n"));
119 ptr += strspn(ptr, ". \t\r\n");
120 *tmp = 0;
122 /* is this the result? */
123 if(!strcmp(t, "1-0"))
125 status = _10;
126 return 1;
128 else if(!strcmp(t, "0-1"))
130 status = _01;
131 return 1;
133 else if(!strcmp(t, "1/2-1/2") || !strcmp(t, "*"))
135 status = _12;
136 return 1;
139 /* is this a move number? */
140 char *e;
141 strtol(t, &e, 10);
142 if(e!=t)
143 continue;
145 Move mv = board.move_from_string(t);
146 if(!mv.valid())
148 board.print_board();
149 output("Error! \"%s\" %x\n", t, mv.as_int);
150 return 0; /* error */
153 mv_done[mv_done_num++] = mv;
154 board.do_move(mv, save_buf[save_buf_num++]);
157 if(!fgets(buf, 1024, f))
158 return 1;
162 int Engine::run_epd_prog(const char* prog, int time, const char* file, bool quiet)
164 char buf[1024];
165 bool failed[8000];
166 FILE *in = NULL;
167 FILE *out = NULL;
168 FILE *f;
170 /* open the file with the tests */
171 f = fopen(file, "r");
172 if(!f)
174 output("Error, could not open %s for reading!\n", file);
175 return 0;
178 if(!strcmp(prog, "self"))
180 if(quiet)
181 post = false;
182 set_time_fixed(time);
184 else
185 start_engine(prog, &in, &out);
187 /* reset passed flags */
188 int done = 0;
189 int passed = 0;
190 for(int i=0;i<8000;i++)
191 failed[i] = false;
193 while(fgets(buf, 1024, f))
195 char brd[81];
196 char color[2],castle[5],passing[3];
197 char best[256];
198 char avoid[256];
199 char name[64];// = "unknown";
200 char *tmp;
201 Move best_mv[10];
202 Move avoid_mv[10];
203 int num_best = 0;
204 int num_avoid = 0;
205 Move m;
208 /* read the board */
209 sscanf(buf,"%s%s%s%s",
210 brd,color,castle,passing);
211 read_board(brd,color,castle,passing,0,0);
212 if(!quiet)
214 output("\n\n");
215 board.print_board();
219 done++;
220 //printf("%s\n", buf);
222 /* save the best moves in the best_mv array */
223 tmp = strstr(buf, "bm");
224 if(tmp)
226 int tok = 0;
227 sscanf(tmp, "bm %63[^;];", best);
228 tok += strspn(best + tok, " \t\r\n");
230 for(num_best=0;num_best<10;num_best++)
232 if(!best[tok])
233 break;
235 int start = tok;
236 int firstspace = (tok += strcspn(best + tok, " \t\r\n"));
237 tok += strspn(best + tok, " \t\r\n");
238 best[firstspace] = 0;
240 best_mv[num_best] = board.move_from_string(best+start);
242 if(!best_mv[num_best].valid())
244 output("Error, could not parse move %s in pos %d\n", best+start, done);
245 return 0;
250 /* save the avoid moves in the best_mv array */
251 tmp = strstr(buf, "am");
252 if(tmp)
254 int tok = 0;
255 sscanf(tmp, "am %63[^;];", avoid);
256 tok += strspn(avoid + tok, " \t\r\n");
258 for(num_avoid=0;num_avoid<10;num_avoid++)
260 if(!avoid[tok])
261 break;
263 int start = tok;
264 int firstspace = (tok += strcspn(avoid + tok, " \t\r\n"));
265 tok += strspn(avoid + tok, " \t\r\n");
266 avoid[firstspace] = 0;
268 avoid_mv[num_avoid] = board.move_from_string(avoid+start);
270 if(!avoid_mv[num_avoid].valid())
272 output("Error, could not parse move %s in pos %d\n", best+start, done);
273 return 0;
278 /* get the id */
279 tmp = strstr(buf, "id");
280 if(tmp)
281 sscanf ( tmp, "id %63[^;];", name);
282 else
283 strcpy( name, "<unknown>" );
285 if(!quiet)
287 output(" %d - Thinking", done);
288 if(num_best)
290 output(", the best move%s\e[32;1m", num_best>1 ? "s are" : " is");
291 for(int i=0;i<num_best;i++)
292 output(" %s", board.move_to_alg(MoveStr().data(), best_mv[i]) );
293 output("\e[0m");
295 if(num_avoid)
297 output(", the move%s to avoid\e[31;1m", num_avoid>1 ? "s are" : " is");
298 for(int i=0;i<num_avoid;i++)
299 output(" %s", board.move_to_alg(MoveStr().data(), avoid_mv[i]) );
300 output("\e[0m");
302 output("\n");
305 if(!strcmp(prog, "self"))
307 st_computer_color = board.color_to_move;
308 m = find_best_move();
310 else
312 fprintf(out, "force\n");
313 fprintf(out, "setboard %s\n", board.to_fen(BigStr().data()) );
314 fprintf(out, "st %d\n", time);
315 //fprintf(out, "level 1 %d 0\n", time);
316 //fprintf(out, "time %d\n", time*100);
317 //fprintf(out, "otim %d\n", time*100);
318 fprintf(out, "post\n");
319 fprintf(out, "go\n");
321 //sleep(1);
322 //fprintf(out, "?\n");
324 while(fgets(buf, 1024, in))
326 char mv[32];
327 if(!strncmp(buf, "move ", 5))
329 sscanf ( buf, "move %s", mv);
330 m = board.move_from_string(mv);
331 if(!m.valid())
333 output("Got illegal move %s\n", mv);
334 return 0;
336 break;
338 if(!quiet)
339 output(buf);
343 bool fail = false;
344 if(!quiet)
345 output("Result: \e[36;1m%s\e[0m\n", board.move_to_alg(MoveStr().data(), m));
346 for(int i=0;i<num_avoid;i++)
347 if(m == avoid_mv[i])
349 fail = true;
350 if(!quiet)
351 output("Test %d \e[31;1mFAILURE\e[0m, %s did not avoid the "
352 "wrong move \e[33;1m%s\e[0m (che pollo!)\n",done, prog,
353 board.move_to_alg(MoveStr().data(), avoid_mv[i]));
355 if(num_avoid && !fail && !quiet)
356 output("Test %d \e[32;1mSUCCESS\e[0m, %s avoided the "
357 "wrong move%s \e[33;1m%s\e[0m (teto figo!)\n",
358 done, prog, num_avoid>1?"s":"", avoid);
359 if(!fail && num_best)
361 fail = true;
362 for(int i=0;i<num_best;i++)
363 if(m == best_mv[i])
365 fail = false;
366 if(!quiet)
367 output("Test %d \e[32;1mSUCCESS\e[0m, %s found the "
368 "best move \e[33;1m%s\e[0m (o se figo!)\n",
369 done, prog, board.move_to_alg(MoveStr().data(), best_mv[i]));
370 break;
372 if(fail && !quiet)
373 output("Test %d \e[31;1mFAILURE\e[0m, %s missed the best "
374 "move%s (\e[33;1m%s\e[0m) (che scarso!)\n", done, prog,
375 num_best>1?"s":"", best);
377 if(!fail)
378 passed++;
379 else
380 failed[done] = true;
382 if(!quiet)
383 output("Test %d %s %s! (+%d, -%d, ~%d%%)\n", done, name, fail ?
384 "\e[31;1mFAILED\e[0m" : "\e[32;1mPASSED\e[0m",
385 passed, done-passed, passed*100/done);
386 else {
387 output("%s", fail ? "-" : "+");
388 char str[80];
389 snprintf(str, 40, "(%d/%d)", passed, done);
390 int l = strlen(str);
391 for(int i=0;i<l;i++)
392 str[l+i] = '\b';
393 fwrite(str, 2*l, 1, stdout);
394 fflush(stdout);
397 if(quiet)
398 output("\n");
399 output("Passed %d tests out of %d (%d%%)\n", passed, done, passed*100/done);
400 if(!quiet)
402 output("Failed are:\n");
403 int numsh = 0;
404 for(int i=1;i<done+1;i++)
405 if(failed[i])
407 output(" %d", i);
408 if(((++numsh) % 10) == 0)
409 output("\n");
411 output("\n");
414 if(strcmp(prog, "self"))
416 fprintf(out, "quit\n");
417 fclose(out);
418 fclose(in);
420 fclose(f);
422 return passed;
425 void Engine::save_pgn(FILE *f, const char *result1, const char *result)
427 for(int i=mv_done_num-1;i>=0;i--)
428 board.undo_move(mv_done[i], save_buf[--save_buf_num]);
430 fprintf(f, "[White \"%s\"]\n", st_computer_color == WHITE ?
431 "RattateChess" : opponent );
432 fprintf(f, "[Black \"%s\"]\n", st_computer_color == BLACK ?
433 "RattateChess" : opponent );
434 fprintf(f, "[WhiteELO \"%d\"]\n", w_rating);
435 fprintf(f, "[BlackELO \"%d\"]\n", b_rating);
437 time_t t = time(NULL);
438 char tbuf[256];
439 strftime(tbuf, 256, "%Y.%m.%d %H:%M", localtime(&t));
440 fprintf(f, "[Date \"%s\"]\n", tbuf);
441 fprintf(f, "[Result \"%s\"]\n", result1);
443 if(0)
444 fprintf(f, "[FEN \"%s\"]\n", board.to_fen(BigStr().data()) );
446 if(board.color_to_move==BLACK)
447 fprintf(f, "%d. ... ",board.num_moves+1);
448 for(int i=0;i<mv_done_num;i++)
450 if(board.color_to_move==WHITE)
451 fprintf(f, "%d. ",board.num_moves+1);
452 fprintf(f, "%s ", board.move_to_alg(MoveStr().data(), mv_done[i]) );
453 if((i+1)%14 == 0 && i!=mv_done_num-1)
454 fprintf(f, "\n");
455 board.do_move(mv_done[i], save_buf[save_buf_num++]);
457 fprintf(f, "\n%s\n\n", result);
460 void Engine::challenge(const char* prog, int time, const char* file)
462 char buf[1024];
463 FILE *in = NULL;
464 FILE *out = NULL;
465 FILE *f;
466 FILE *log;
467 int won=0, draw=0, lost=0;
469 /* open the file with the tests */
470 f = fopen(file, "r");
471 log = fopen("challenge.pgn", "w");
473 if(!f)
475 output("Error, could not open %s for reading!\n", file);
476 return;
479 start_engine(prog, &in, &out);
481 while(fgets(buf, 1024, f))
483 uint8_t cols[2] = {WHITE, BLACK};
485 for(int i=0;i<2;i++)
487 bool go_done = false;
488 read_board(buf);
489 //set_max_nodes(time);
490 set_time_fixed(time);
491 //set_time_control(40, time, 0);
492 ponder = false;
494 fprintf(out, "new\n");
495 fprintf(out, "st %d\n", time);
496 //fprintf(out, "level 40 %d:%d 0\n", time/60, time%60);
497 fprintf(out, "force\n");
498 fprintf(out, "setboard %s\n", board.to_fen(BigStr().data()));
501 status = PLAYING;
502 st_computer_color = cols[i];
504 while(1)
506 char buf[1024];
508 output("\n\n");
509 board.print_board();
511 /* print the pgn to the log file */
512 if(status != PLAYING)
514 const char *result = status==_01?"0-1":(status==_10?"1-0":"1/2-1/2");
515 const char *white = st_computer_color == WHITE ? "Rattatechess" : prog;
516 const char *black = st_computer_color == BLACK ? "Rattatechess" : prog;
518 if(log)
520 for(int i=mv_done_num-1;i>=0;i--)
521 board.undo_move(mv_done[i], save_buf[--save_buf_num]);
523 fprintf(log, "[White \"%s\"]\n", white);
524 fprintf(log, "[Black \"%s\"]\n", black);
525 fprintf(log, "[Result \"%s\"]\n", result);
526 fprintf(log, "[FEN \"%s\"]\n", board.to_fen(BigStr().data()) );
528 if(board.color_to_move==BLACK)
529 fprintf(log, "%d. ... ",board.num_moves+1);
530 for(int i=0;i<mv_done_num;i++)
532 if(board.color_to_move==WHITE)
533 fprintf(log, "%d. ",board.num_moves+1);
534 fprintf(log, "%s ", board.move_to_alg(MoveStr().data(), mv_done[i]) );
535 if((i+1)%14 == 0)
536 fprintf(log, "\n");
537 board.do_move(mv_done[i], save_buf[save_buf_num++]);
539 fprintf(log, "%s\n\n", result);
540 fflush(log);
543 if((status==_01 && st_computer_color==BLACK) ||
544 (status==_10 && st_computer_color==WHITE))
546 output("RATTA!!!\n");
547 won++;
549 else if(status==_12)
551 output("DRAW!\n");
552 draw++;
554 else
556 output("ARGH!!!\n");
557 lost++;
559 break;
562 /* think or wait for a new move */
563 if(st_computer_color == board.color_to_move)
565 /* think and move */
566 Move mv = find_best_move();
567 output("%d. %s %s\n",board.num_moves+1,
568 board.color_to_move==BLACK ? "..." : "",
569 board.move_to_alg(MoveStr().data(), mv) );
570 fprintf( out, "%s\n", Board::move_to_coord(MoveStr().data(), mv));
571 move(mv);
573 else
575 if(!go_done)
577 fprintf( out, "go\n");
578 go_done = true;
581 while(fgets(buf, 1024, in))
583 /* get a move from the other engine */
584 if(!strncmp(buf, "move ", 5))
586 Move mv;
587 char buf2[32];
588 sscanf( buf, "move %s", buf2);
589 mv = board.move_from_string(buf2);
590 if(!mv.valid())
592 output("Got illegal move %s\n", buf2);
593 return;
595 output("%d. %s %s\n",board.num_moves+1,
596 board.color_to_move==BLACK ? "..." : "",
597 board.move_to_alg(MoveStr().data(), mv) );
598 move(mv);
599 break;
601 else if(!strcmp(buf, "resign"))
603 status = board.color_to_move==WHITE?_01:_10;
604 break;
606 //else
607 // output(buf);
614 fprintf(out, "quit\n");
615 fclose(out);
616 fclose(in);
617 if(log) fclose(log);
618 fclose(f);
620 output("\n\n%d games played (+%d =%d -%d)\n", won+draw+lost, won, draw, lost);