more eval tunings.
[rattatechess.git] / moveparse.cpp
blob4371bc4e3da48cb0dfd5279f21b068a95828ca55
1 /***************************************************************************
2 moveparse.cpp - description
3 -------------------
4 begin : mer ott 30 2002
5 copyright : (C) 2002-2005 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 //reads a string and if possible understand a move
23 //in the current position
24 //the board must be the board before the move is done
26 static int char_to_piece(char c)
28 switch(c)
30 case 'K': case 'k': return KING;
31 case 'Q': case 'q': return QUEEN;
32 case 'R': case 'r': return ROOK;
33 case 'B': case 'b': return BISHOP;
34 case 'N': case 'n': return KNIGHT;
35 case 'P': case 'p': return PAWN;
38 return -1;
41 int Engine::parse_move(Move* mv,char* s)
43 int piece = -1;
44 int from_x = -1;
45 int from_y = -1;
46 int to_x = -1;
47 int to_y = -1;
48 int promote = -1;
49 int comment_1 = 0;
50 int comment_2 = strlen(s);
51 int pos = 0;
53 /* parse O-O-O */
54 if(!strncmp(s, "0-0-0", 5) || !strncmp(s, "O-O-O", 5) || !strncmp(s, "o-o-o", 5) )
56 comment_1 = 5;
58 Move moves[250];
59 int num_moves = board.find_moves(moves);
61 for(int i=0;i<num_moves;i++)
62 if(moves[i].flags == CASTLEQUEENSIDE)
64 *mv = moves[i];
65 goto do_return;
68 output("Illegal move: %s\n", s);
69 return 2;
72 /* parse O-O. Note that O-O-O matches the expr for O-O, so it must be tested after */
73 if(!strncmp(s, "0-0", 3) || !strncmp(s, "O-O", 3) || !strncmp(s, "o-o", 3) )
75 comment_1 = 3;
77 Move moves[250];
78 int num_moves = board.find_moves(moves);
80 for(int i=0;i<num_moves;i++)
81 if(moves[i].flags == CASTLEKINGSIDE)
83 *mv = moves[i];
84 goto do_return;
87 output("Illegal move: %s\n", s);
88 return 2;
91 /* parse a SAN */
92 if(s[pos]>='A' && s[pos]<='Z' && (piece=char_to_piece(s[pos])) != -1)
93 pos++;
94 if(s[pos]>='a' && s[pos]<='h')
95 to_x = s[pos++] - 'a';
96 if(s[pos]>='1' && s[pos]<='8')
97 to_y = s[pos++] - '1';
98 if(s[pos]=='-' || s[pos]=='x')
99 pos++;
100 if(s[pos]>='A' && s[pos]<='Z' && char_to_piece(s[pos]) != -1)
101 pos++;
102 if(s[pos]>='a' && s[pos]<='h')
104 from_x = to_x;
105 to_x = s[pos++] - 'a';
107 if(s[pos]>='1' && s[pos]<='8')
109 from_y = to_y;
110 to_y = s[pos++] - '1';
112 if(s[pos]=='=')
113 pos++;
114 if((promote=char_to_piece(s[pos])) != -1)
115 pos++;
117 if(to_x != -1 && to_y != -1)
119 if(piece==-1 && (from_x==-1 || from_y==-1))
120 piece = PAWN;
122 comment_1 = pos;
124 /* find a unique matching move */
125 Move moves[250];
126 int num_moves = board.find_moves(moves);
127 bool found = false;
129 // board.print_board();
130 // printf("piece=%d from_x=%d from_y=%d to_x=%d to_y=%d promote=%d\n",
131 // piece, from_x, from_y, to_x, to_y, promote);
133 for(int i=0;i<num_moves;i++)
135 // char buf[64];
136 // move_to_alg(buf, &moves[i]);
137 // printf("%s piece=%d from_x=%d from_y=%d to_x=%d to_y=%d promote=%d\n", buf,
138 // PIECE_OF(board.data[moves[i].from]), X(moves[i].from), Y(moves[i].from),
139 // X(moves[i].to), Y(moves[i].to), moves[i].flags);
140 if( (piece == -1 || piece == PIECE_OF(board.data[moves[i].from])) &&
141 (from_x == -1 || from_x == X(moves[i].from)) &&
142 (from_y == -1 || from_y == Y(moves[i].from)) &&
143 (to_x == X(moves[i].to)) &&
144 (to_y == Y(moves[i].to)) &&
145 (moves[i].flags<PROMOTE_FIRST || moves[i].flags>PROMOTE_LAST || moves[i].flags-PROMOTE0 == promote) )
147 if(found)
149 output("Illegal move (ambiguous): %s\n", s);
150 return 3;
152 else
154 //printf("Found!\n");
155 found = true;
156 *mv = moves[i];
161 if(!found)
163 output("Illegal move: %s\n", s);
164 return 2;
167 goto do_return;
170 return 0;
172 do_return:
173 mv->val = 0;
174 for(int i=comment_1; i<comment_2; i++)
175 if(s[i] == '!')
176 mv->val++;
177 else if(s[i] == '?')
178 mv->val--;
180 return 1;
183 //converts a move to the dummy notation (e2e4,g7h8q,...)
184 char* Engine::move_to_coord(char* string,Move* mv)
186 char* str = string;
187 *(str++) = 'a' + X(mv->from);
188 *(str++) = '1' + Y(mv->from);
189 *(str++) = 'a' + X(mv->to);
190 *(str++) = '1' + Y(mv->to);
192 /* promotion */
193 if(mv->flags > PROMOTE0)
194 *(str++) = Board::piecename[ mv->flags-PROMOTE0 ]^0x20;
195 *(str++)='\0';
196 return string;
199 /* converts a move into the standard algebraic notation
200 the current board must be the board before the move is done.
201 mv must be a valid move in the current position! */
202 char* Engine::move_to_alg(char* string,Move* mv)
204 char* str=string;
206 if(mv->flags==CASTLEKINGSIDE)
208 *(str++)='O';
209 *(str++)='-';
210 *(str++)='O';
212 else if(mv->flags==CASTLEQUEENSIDE)
214 *(str++)='O';
215 *(str++)='-';
216 *(str++)='O';
217 *(str++)='-';
218 *(str++)='O';
220 else
222 Move moves[200];
223 int num_moves = board.find_moves(moves);
224 unsigned char piece=board.data[mv->from];
226 if(PIECE_OF(piece)!=PAWN)
228 /* mark here how the move could be ambiguous */
229 bool ambig = false;
230 bool samecol=false;
231 bool samerow=false;
233 *(str++)=Board::piecename[PIECE_OF(piece)];
235 for(int i=0;i<num_moves;i++)
237 //check for ambiguity
238 if(piece == board.data[moves[i].from] //same piece?
239 && moves[i].to == mv->to //same target?
240 && moves[i].from != mv->from) //but not same move?
242 ambig = true;
243 if(X(moves[i].from)==X(mv->from))
244 samecol=true;
245 if(Y(moves[i].from)==Y(mv->from))
246 samerow=true;
250 if(ambig)
252 if(!samecol || samerow)
253 *(str++)='a' + X(mv->from);
254 if(samecol)
255 *(str++)='1' + Y(mv->from);
258 if((mv->capture) || mv->flags==ENPASSANT)
260 if(PIECE_OF(piece)==PAWN)
261 *(str++)='a' + X(mv->from);
262 *(str++)='x';
265 *(str++)='a' + X(mv->to);
266 *(str++)='1' + Y(mv->to);
268 if(mv->flags > PROMOTE0)
270 *(str++) = '=';
271 *(str++) = Board::piecename[ mv->flags-PROMOTE0 ];
274 /* is this move a check(mate)? */
275 board.do_move(*mv);
276 if(board.under_attack( board.king_pos[IS_WHITE(board.color_to_move)],
277 board.other_color) )
279 Move mv_tmp[200];
280 int n = board.find_moves(mv_tmp);
282 if(n==0)
283 *(str++)='#';
284 else
285 *(str++)='+';
287 board.undo_move(*mv);
288 *(str++)='\0';
289 return string;
292 void Engine::print_moves(Move* m,int num,bool nums)
294 int i,j;
295 if(board.color_to_move==BLACK &&nums)
296 output("%d. ...",board.num_moves+1);
298 for(i=0;i<num;i++)
300 char str[32];
301 if(m[i].as_int == 0)
302 break;
304 if(board.color_to_move==WHITE && nums)
305 printf(" %d.",board.num_moves+1);
306 output( " %s", move_to_alg(str,m+i) );
307 board.do_move(m[i]);
310 Move hash_mv[24];
311 int prev_depth = 0;
312 for(j=0;j<24-i;j++)
314 HashEntry *h = probe_hash( board.hash );
315 if(!h || !h->best_mv)
316 break;
318 /* don't follow the hash if there is draw for repetition :) */
319 if(j==0)
320 prev_depth = h->depth;
321 //if(h->depth > prev_depth)
322 if( check_draw() )
324 output( " <DRAW>" );
325 break;
328 hash_mv[j] = board.uncompress_move( h->best_mv );
330 /* rerity taht the move in the hash is a legal move */
331 Move tmp[255];
332 int num_tmp = board.find_moves(tmp);
333 bool ok = false;
334 for(int q=0;q<num_tmp;q++)
335 if(tmp[q] == hash_mv[j])
337 ok = true;
338 break;
341 if(!ok)
342 break;
344 printf("QUEEEEEEEEEEEEEEE2!!!!!!!!!!\n");
345 board.print_board();
346 exit(0);
349 char str[32];
350 if(board.color_to_move==WHITE && nums)
351 output(" %d.",board.num_moves+1);
352 output( " %s", move_to_alg(str,hash_mv+j) );
353 board.do_move(hash_mv[j]);
356 while(j--)
357 board.undo_move(hash_mv[j]);
359 while(i--)
360 board.undo_move(m[i]);
362 output("\n");
365 /* TODO: load correctly the pgn that start with a fen */
366 int Engine::load_pgn(FILE *f)
368 char buf[1024];
370 board.set_as_default();
371 mv_done_num = 0;
373 while(1)
375 if(!fgets(buf, 1024, f))
376 return 0;
377 if(buf[0]=='\n' || buf[0]=='\r' || buf[0]=='\t'
378 || buf[0]==' ' || buf[0]=='[' || buf[0]=='#')
379 continue;
380 break;
383 while(1)
385 char *ptr = buf;
386 ptr += strspn(ptr, ". \t\r\n");
388 for(int i=0;;i++)
390 if(!*ptr)
391 break;
392 char *t = ptr;
393 char *tmp = (ptr += strcspn(ptr, ". \t\r\n"));
394 ptr += strspn(ptr, ". \t\r\n");
395 *tmp = 0;
397 /* is this the result? */
398 if(!strcmp(t, "1-0"))
400 status = _10;
401 return 1;
403 else if(!strcmp(t, "0-1"))
405 status = _01;
406 return 1;
408 else if(!strcmp(t, "1/2-1/2") || !strcmp(t, "*"))
410 status = _12;
411 return 1;
414 /* is this a move number? */
415 char *e;
416 strtol(t, &e, 10);
417 if(e!=t)
418 continue;
420 Move mv;
421 int retv = parse_move(&mv, t);
422 if(retv != 1)
424 board.print_board();
425 output("Error! \"%s\" %d\n", t, retv);
426 return 0; /* error */
429 mv_done[mv_done_num++] = mv;
430 board.do_move(mv);
433 if(!fgets(buf, 1024, f))
434 return 1;
438 int Engine::run_epd_prog(const char* prog, int time, const char* file, bool quiet)
440 char buf[1024];
441 bool failed[8000];
442 FILE *in = NULL;
443 FILE *out = NULL;
444 FILE *f;
446 /* open the file with the tests */
447 f = fopen(file, "r");
448 if(!f)
450 output("Error, could not open %s for reading!\n", file);
451 return 0;
454 if(!strcmp(prog, "self"))
456 if(quiet)
457 post = false;
458 set_time_fixed(time);
460 else
461 start_engine(prog, &in, &out);
463 /* reset passed flags */
464 int done = 0;
465 int passed = 0;
466 for(int i=0;i<8000;i++)
467 failed[i] = false;
469 while(fgets(buf, 1024, f))
471 char brd[81];
472 char color[2],castle[5],passing[3];
473 char best[256];
474 char avoid[256];
475 char name[64];// = "unknown";
476 char *tmp;
477 Move best_mv[10];
478 Move avoid_mv[10];
479 int num_best = 0;
480 int num_avoid = 0;
481 Move m;
484 /* read the board */
485 sscanf(buf,"%s%s%s%s",
486 brd,color,castle,passing);
487 read_board(brd,color,castle,passing,0,0);
488 if(!quiet)
490 output("\n\n");
491 board.print_board();
495 done++;
496 //printf("%s\n", buf);
498 /* save the best moves in the best_mv array */
499 tmp = strstr(buf, "bm");
500 if(tmp)
502 int tok = 0;
503 sscanf(tmp, "bm %63[^;];", best);
504 tok += strspn(best + tok, " \t\r\n");
506 for(num_best=0;num_best<10;num_best++)
508 if(!best[tok])
509 break;
511 int start = tok;
512 int firstspace = (tok += strcspn(best + tok, " \t\r\n"));
513 tok += strspn(best + tok, " \t\r\n");
514 best[firstspace] = 0;
516 //printf("bmv -> %s\n", best+start);
518 if(parse_move(&best_mv[num_best], best+start) != 1)
520 output("Error, could not parse move %s in pos %d\n", best+start, done);
521 return 0;
526 /* save the avoid moves in the best_mv array */
527 tmp = strstr(buf, "am");
528 if(tmp)
530 int tok = 0;
531 sscanf(tmp, "am %63[^;];", avoid);
532 tok += strspn(avoid + tok, " \t\r\n");
534 for(num_avoid=0;num_avoid<10;num_avoid++)
536 if(!avoid[tok])
537 break;
539 int start = tok;
540 int firstspace = (tok += strcspn(avoid + tok, " \t\r\n"));
541 tok += strspn(avoid + tok, " \t\r\n");
542 avoid[firstspace] = 0;
544 //printf("amv -> %s\n", avoid+start);
546 if(parse_move(&avoid_mv[num_avoid], avoid+start) != 1)
548 output("Error, could not parse move %s in pos %d\n", best+start, done);
549 return 0;
554 /* get the id */
555 tmp = strstr(buf, "id");
556 if(tmp)
557 sscanf ( tmp, "id %63[^;];", name);
558 else
559 strcpy( name, "<unknown>" );
561 if(!quiet)
563 output(" %d - Thinking", done);
564 if(num_best)
566 output(", the best move%s\e[32;1m", num_best>1 ? "s are" : " is");
567 for(int i=0;i<num_best;i++)
568 output(" %s", move_to_alg(buf, &best_mv[i]) );
569 output("\e[0m");
571 if(num_avoid)
573 output(", the move%s to avoid\e[31;1m", num_avoid>1 ? "s are" : " is");
574 for(int i=0;i<num_avoid;i++)
575 output(" %s", move_to_alg(buf, &avoid_mv[i]) );
576 output("\e[0m");
578 output("\n");
581 if(!strcmp(prog, "self"))
583 st_computer_color = board.color_to_move;
584 m = find_best_move();
586 else
588 fprintf(out, "force\n");
589 board.write_board(buf);
590 fprintf(out, "setboard %s\n", buf);
591 fprintf(out, "st %d\n", time);
592 //fprintf(out, "level 1 %d 0\n", time);
593 fprintf(out, "time %d\n", time*200);
594 fprintf(out, "otim %d\n", time*200);
595 fprintf(out, "go\n");
597 while(fgets(buf, 1024, in))
599 char mv[32];
600 if(!strncmp(buf, "move ", 5))
602 sscanf ( buf, "move %s", mv);
603 if(parse_move( &m, mv )!=1)
605 output("Got illegal move %s\n", mv);
606 return 0;
608 break;
610 else
611 output(buf);
615 bool fail = false;
616 if(!quiet)
617 output("Result: \e[36;1m%s\e[0m\n", move_to_alg(buf, &m));
618 for(int i=0;i<num_avoid;i++)
619 if(m == avoid_mv[i])
621 fail = true;
622 if(!quiet)
623 output("Test %d \e[31;1mFAILURE\e[0m, %s did not avoid the "
624 "wrong move \e[33;1m%s\e[0m (che pollo!)\n",done, prog,
625 move_to_alg(buf, &avoid_mv[i]));
627 if(num_avoid && !fail && !quiet)
628 output("Test %d \e[32;1mSUCCESS\e[0m, %s avoided the "
629 "wrong move%s \e[33;1m%s\e[0m (teto figo!)\n",
630 done, prog, num_avoid>1?"s":"", avoid);
631 if(!fail && num_best)
633 fail = true;
634 for(int i=0;i<num_best;i++)
635 if(m == best_mv[i])
637 fail = false;
638 if(!quiet)
639 output("Test %d \e[32;1mSUCCESS\e[0m, %s found the "
640 "best move \e[33;1m%s\e[0m (o se figo!)\n",
641 done, prog, move_to_alg(buf, &best_mv[i]));
642 break;
644 if(fail && !quiet)
645 output("Test %d \e[31;1mFAILURE\e[0m, %s missed the best "
646 "move%s (\e[33;1m%s\e[0m) (che scarso!)\n", done, prog,
647 num_best>1?"s":"", best);
649 if(!fail)
650 passed++;
651 else
652 failed[done] = true;
654 if(!quiet)
655 output("Test %d %s %s! (+%d, -%d, ~%d%%)\n", done, name, fail ?
656 "\e[31;1mFAILED\e[0m" : "\e[32;1mPASSED\e[0m",
657 passed, done-passed, passed*100/done);
658 else
659 output("%s", fail ? "-" : "+");
661 if(quiet)
662 output("\n");
663 output("Passed %d tests out of %d (%d%%)\n", passed, done, passed*100/done);
664 if(!quiet)
666 output("Failed are:\n");
667 int numsh = 0;
668 for(int i=1;i<done+1;i++)
669 if(failed[i])
671 output(" %d", i);
672 if(((++numsh) % 10) == 0)
673 output("\n");
675 output("\n");
678 if(strcmp(prog, "self"))
680 fprintf(out, "quit\n");
681 fclose(out);
682 fclose(in);
684 fclose(f);
686 return passed;
689 void Engine::save_pgn(FILE *f, const char *result1, const char *result)
691 for(int i=mv_done_num-1;i>=0;i--)
692 board.undo_move(mv_done[i]);
694 fprintf(f, "[White \"%s\"]\n", st_computer_color == WHITE ?
695 "RattateChess" : opponent );
696 fprintf(f, "[Black \"%s\"]\n", st_computer_color == BLACK ?
697 "RattateChess" : opponent );
698 fprintf(f, "[WhiteELO \"%d\"]\n", w_rating);
699 fprintf(f, "[BlackELO \"%d\"]\n", b_rating);
701 time_t t = time(NULL);
702 char tbuf[256];
703 strftime(tbuf, 256, "%Y.%m.%d %H:%M", localtime(&t));
704 fprintf(f, "[Date \"%s\"]\n", tbuf);
705 fprintf(f, "[Result \"%s\"]\n", result1);
707 if(0)
709 char fen[256];
710 board.write_board(fen);
711 fprintf(f, "[FEN \"%s\"]\n", fen);
714 if(board.color_to_move==BLACK)
715 fprintf(f, "%d. ... ",board.num_moves+1);
716 for(int i=0;i<mv_done_num;i++)
718 char buf[32];
719 if(board.color_to_move==WHITE)
720 fprintf(f, "%d. ",board.num_moves+1);
721 fprintf(f, "%s ", move_to_alg(buf, &mv_done[i]) );
722 if((i+1)%14 == 0 && i!=mv_done_num-1)
723 fprintf(f, "\n");
724 board.do_move(mv_done[i]);
726 fprintf(f, "\n%s\n\n", result);
729 void Engine::challenge(const char* prog, int time, const char* file)
731 char buf[1024];
732 FILE *in = NULL;
733 FILE *out = NULL;
734 FILE *f;
735 FILE *log;
736 int won=0, draw=0, lost=0;
738 /* open the file with the tests */
739 f = fopen(file, "r");
740 log = fopen("challenge.pgn", "w");
742 if(!f)
744 output("Error, could not open %s for reading!\n", file);
745 return;
748 start_engine(prog, &in, &out);
750 while(fgets(buf, 1024, f))
752 uint8_t cols[2] = {WHITE, BLACK};
754 for(int i=0;i<2;i++)
756 char fen[256];
757 bool go_done = false;
758 read_board(buf);
759 //set_max_nodes(time);
760 set_time_fixed(time);
761 ponder = false;
762 board.write_board(fen);
764 fprintf(out, "new\n");
765 fprintf(out, "st %d\n", time);
766 //fprintf(out, "level 1 %d 0\n", time);
767 fprintf(out, "force\n");
768 fprintf(out, "setboard %s\n", fen);
771 status = PLAYING;
772 st_computer_color = cols[i];
774 while(1)
776 char buf[1024];
778 /*output("\n\n");
779 board.print_board();*/
781 /* print the pgn to the log file */
782 if(status != PLAYING)
784 const char *result = status==_01?"0-1":(status==_10?"1-0":"1/2-1/2");
785 const char *white = st_computer_color == WHITE ? "Rattatechess" : prog;
786 const char *black = st_computer_color == BLACK ? "Rattatechess" : prog;
788 if(log)
790 for(int i=mv_done_num-1;i>=0;i--)
791 board.undo_move(mv_done[i]);
793 fprintf(log, "[White \"%s\"]\n", white);
794 fprintf(log, "[Black \"%s\"]\n", black);
795 fprintf(log, "[Result \"%s\"]\n", result);
796 fprintf(log, "[FEN \"%s\"]\n", fen);
798 if(board.color_to_move==BLACK)
799 fprintf(log, "%d. ... ",board.num_moves+1);
800 for(int i=0;i<mv_done_num;i++)
802 char buf[32];
803 if(board.color_to_move==WHITE)
804 fprintf(log, "%d. ",board.num_moves+1);
805 fprintf(log, "%s ", move_to_alg(buf, &mv_done[i]) );
806 if((i+1)%14 == 0)
807 fprintf(log, "\n");
808 board.do_move(mv_done[i]);
810 fprintf(log, "%s\n\n", result);
811 fflush(log);
814 if((status==_01 && st_computer_color==BLACK) ||
815 (status==_10 && st_computer_color==WHITE))
817 output("RATTA!!!\n");
818 won++;
820 else if(status==_12)
822 output("DRAW!\n");
823 draw++;
825 else
827 output("ARGH!!!\n");
828 lost++;
830 break;
833 /* think or wait for a new move */
834 if(st_computer_color == board.color_to_move)
836 char buf2[32];
838 /* think and move */
839 Move mv = find_best_move();
840 output("%d. %s %s\n",board.num_moves+1,
841 board.color_to_move==BLACK ? "..." : "",
842 move_to_alg(buf2, &mv) );
843 fprintf( out, "%s\n", move_to_coord(buf2,&mv));
844 move(mv);
846 else
848 if(!go_done)
850 fprintf( out, "go\n");
851 go_done = true;
854 while(fgets(buf, 1024, in))
856 /* get a move from the other engine */
857 if(!strncmp(buf, "move ", 5))
859 Move mv;
860 char buf2[32];
861 sscanf( buf, "move %s", buf2);
862 if(parse_move( &mv, buf2 )!=1)
864 output("Got illegal move %s\n", buf2);
865 return;
867 output("%d. %s %s\n",board.num_moves+1,
868 board.color_to_move==BLACK ? "..." : "",
869 move_to_alg(buf2, &mv) );
870 move(mv);
871 break;
873 else if(!strcmp(buf, "resign"))
875 status = board.color_to_move==WHITE?_01:_10;
876 break;
878 //else
879 // output(buf);
886 fprintf(out, "quit\n");
887 fclose(out);
888 fclose(in);
889 if(log) fclose(log);
890 fclose(f);
892 output("\n\n%d games played (+%d =%d -%d)\n", won+draw+lost, won, draw, lost);