Removed another useless file.
[rattatechess.git] / moveparse.cpp
blob8dc902721ac3f7f9e7098a67c3462d43c05bbb02
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 for(int i=0;i<num_moves;i++)
131 if( (piece == -1 || piece == PIECE_OF(board.data[moves[i].from])) &&
132 (from_x == -1 || from_x == X(moves[i].from)) &&
133 (from_y == -1 || from_y == Y(moves[i].from)) &&
134 (to_x == X(moves[i].to)) &&
135 (to_y == Y(moves[i].to)) &&
136 (moves[i].flags<=PROMOTE0 || moves[i].flags-PROMOTE0 == promote) )
138 if(found)
140 output("Illegal move (ambiguous): %s\n", s);
141 return 3;
143 else
145 found = true;
146 *mv = moves[i];
151 if(!found)
153 output("Illegal move: %s\n", s);
154 return 2;
157 goto do_return;
160 return 0;
162 do_return:
163 mv->val = 0;
164 for(int i=comment_1; i<comment_2; i++)
165 if(s[i] == '!')
166 mv->val++;
167 else if(s[i] == '?')
168 mv->val--;
170 return 1;
173 //converts a move to the dummy notation (e2e4,g7h8q,...)
174 char* Engine::move_to_coord(char* string,Move* mv)
176 char* str = string;
177 *(str++) = 'a' + X(mv->from);
178 *(str++) = '1' + Y(mv->from);
179 *(str++) = 'a' + X(mv->to);
180 *(str++) = '1' + Y(mv->to);
182 /* promotion */
183 if(mv->flags > PROMOTE0)
184 *(str++) = Board::piecename[ mv->flags-PROMOTE0 ]^0x20;
185 *(str++)='\0';
186 return string;
189 /* converts a move into the standard algebraic notation
190 the current board must be the board before the move is done.
191 mv must be a valid move in the current position! */
192 char* Engine::move_to_alg(char* string,Move* mv)
194 char* str=string;
196 if(mv->flags==CASTLEKINGSIDE)
198 *(str++)='O';
199 *(str++)='-';
200 *(str++)='O';
202 else if(mv->flags==CASTLEQUEENSIDE)
204 *(str++)='O';
205 *(str++)='-';
206 *(str++)='O';
207 *(str++)='-';
208 *(str++)='O';
210 else
212 Move moves[200];
213 int num_moves = board.find_moves(moves);
214 unsigned char piece=board.data[mv->from];
216 if(PIECE_OF(piece)!=PAWN)
218 /* mark here how the move could be ambiguous */
219 bool ambig = false;
220 bool samecol=false;
221 bool samerow=false;
223 *(str++)=Board::piecename[PIECE_OF(piece)];
225 for(int i=0;i<num_moves;i++)
227 //check for ambiguity
228 if(piece == board.data[moves[i].from] //same piece?
229 && moves[i].to == mv->to //same target?
230 && moves[i].from != mv->from) //but not same move?
232 ambig = true;
233 if(X(moves[i].from)==X(mv->from))
234 samecol=true;
235 if(Y(moves[i].from)==Y(mv->from))
236 samerow=true;
240 if(ambig)
242 if(!samecol || samerow)
243 *(str++)='a' + X(mv->from);
244 if(samecol)
245 *(str++)='1' + Y(mv->from);
248 if((mv->capture) || mv->flags==ENPASSANT)
250 if(PIECE_OF(piece)==PAWN)
251 *(str++)='a' + X(mv->from);
252 *(str++)='x';
255 *(str++)='a' + X(mv->to);
256 *(str++)='1' + Y(mv->to);
258 if(mv->flags > PROMOTE0)
260 *(str++) = '=';
261 *(str++) = Board::piecename[ mv->flags-PROMOTE0 ];
264 /* is this move a check(mate)? */
265 board.do_move(*mv);
266 if(board.under_attack( board.king_pos[IS_WHITE(board.color_to_move)],
267 board.other_color) )
269 Move mv_tmp[200];
270 int n = board.find_moves(mv_tmp);
272 if(n==0)
273 *(str++)='#';
274 else
275 *(str++)='+';
277 board.undo_move(*mv);
278 *(str++)='\0';
279 return string;
282 void Engine::print_moves(Move* m,int num,bool nums)
284 int i,j;
285 if(board.color_to_move==BLACK &&nums)
286 output("%d. ...",board.num_moves+1);
288 for(i=0;i<num;i++)
290 char str[32];
291 if(m[i].as_int == 0)
292 break;
294 if(board.color_to_move==WHITE && nums)
295 printf(" %d.",board.num_moves+1);
296 output( " %s", move_to_alg(str,m+i) );
297 board.do_move(m[i]);
300 Move hash_mv[24];
301 int prev_depth = 0;
302 for(j=0;j<24-i;j++)
304 HashEntry *h = probe_hash( board.hash );
305 if(!h || !h->best_mv)
306 break;
308 /* don't follow the hash if there is draw for repetition :) */
309 if(j==0)
310 prev_depth = h->depth;
311 //if(h->depth > prev_depth)
312 if( check_draw() )
314 output( " <DRAW>" );
315 break;
318 hash_mv[j] = board.uncompress_move( h->best_mv );
320 /* rerity taht the move in the hash is a legal move */
321 Move tmp[255];
322 int num_tmp = board.find_moves(tmp);
323 bool ok = false;
324 for(int q=0;q<num_tmp;q++)
325 if(tmp[q] == hash_mv[j])
327 ok = true;
328 break;
331 if(!ok)
332 break;
334 printf("QUEEEEEEEEEEEEEEE2!!!!!!!!!!\n");
335 board.print_board();
336 exit(0);
339 char str[32];
340 if(board.color_to_move==WHITE && nums)
341 output(" %d.",board.num_moves+1);
342 output( " %s", move_to_alg(str,hash_mv+j) );
343 board.do_move(hash_mv[j]);
346 while(j--)
347 board.undo_move(hash_mv[j]);
349 while(i--)
350 board.undo_move(m[i]);
352 output("\n");
355 /* TODO: load correctly the pgn that start with a fen */
356 int Engine::load_pgn(FILE *f)
358 char buf[1024];
360 board.set_as_default();
361 mv_done_num = 0;
363 while(1)
365 if(!fgets(buf, 1024, f))
366 return 0;
367 if(buf[0]=='\n' || buf[0]=='\r' || buf[0]=='\t'
368 || buf[0]==' ' || buf[0]=='[' || buf[0]=='#')
369 continue;
370 break;
373 while(1)
375 char *ptr = buf;
376 ptr += strspn(ptr, ". \t\r\n");
378 for(int i=0;;i++)
380 if(!*ptr)
381 break;
382 char *t = ptr;
383 char *tmp = (ptr += strcspn(ptr, ". \t\r\n"));
384 ptr += strspn(ptr, ". \t\r\n");
385 *tmp = 0;
387 /* is this the result? */
388 if(!strcmp(t, "1-0"))
390 status = _10;
391 return 1;
393 else if(!strcmp(t, "0-1"))
395 status = _01;
396 return 1;
398 else if(!strcmp(t, "1/2-1/2") || !strcmp(t, "*"))
400 status = _12;
401 return 1;
404 /* is this a move number? */
405 char *e;
406 strtol(t, &e, 10);
407 if(e!=t)
408 continue;
410 Move mv;
411 int retv = parse_move(&mv, t);
412 if(retv != 1)
414 board.print_board();
415 output("Error! \"%s\" %d\n", t, retv);
416 return 0; /* error */
419 mv_done[mv_done_num++] = mv;
420 board.do_move(mv);
423 if(!fgets(buf, 1024, f))
424 return 1;
428 int Engine::run_epd_prog(const char* prog, int time, const char* file, bool quiet)
430 char buf[1024];
431 bool failed[8000];
432 FILE *in = NULL;
433 FILE *out = NULL;
434 FILE *f;
436 /* open the file with the tests */
437 f = fopen(file, "r");
438 if(!f)
440 output("Error, could not open %s for reading!\n", file);
441 return 0;
444 if(!strcmp(prog, "self"))
446 if(quiet)
447 post = false;
448 set_time_fixed(time);
450 else
451 start_engine(prog, &in, &out);
453 /* reset passed flags */
454 int done = 0;
455 int passed = 0;
456 for(int i=0;i<8000;i++)
457 failed[i] = false;
459 while(fgets(buf, 1024, f))
461 char brd[81];
462 char color[2],castle[5],passing[3];
463 char best[256];
464 char avoid[256];
465 char name[64];// = "unknown";
466 char *tmp;
467 Move best_mv[10];
468 Move avoid_mv[10];
469 int num_best = 0;
470 int num_avoid = 0;
471 Move m;
474 /* read the board */
475 sscanf(buf,"%s%s%s%s",
476 brd,color,castle,passing);
477 read_board(brd,color,castle,passing,0,0);
478 if(!quiet)
480 output("\n\n");
481 board.print_board();
485 done++;
487 /* save the best moves in the best_mv array */
488 tmp = strstr(buf, "bm");
489 if(tmp)
491 int tok = 0;
492 sscanf(tmp, "bm %63[^;];", best);
493 tok += strspn(best + tok, " \t\r\n");
495 for(num_best=0;num_best<10;num_best++)
497 if(!best[tok])
498 break;
500 int start = tok;
501 int firstspace = (tok += strcspn(best + tok, " \t\r\n"));
502 tok += strspn(best + tok, " \t\r\n");
503 best[firstspace] = 0;
505 if(parse_move(&best_mv[num_best], best+start) != 1)
507 output("Error, could not parse move %s in pos %d\n", best+start, done);
508 return 0;
513 /* save the avoid moves in the best_mv array */
514 tmp = strstr(buf, "am");
515 if(tmp)
517 int tok = 0;
518 sscanf(tmp, "am %63[^;];", avoid);
519 tok += strspn(avoid + tok, " \t\r\n");
521 for(num_avoid=0;num_avoid<10;num_avoid++)
523 if(!avoid[tok])
524 break;
526 int start = tok;
527 int firstspace = (tok += strcspn(avoid + tok, " \t\r\n"));
528 tok += strspn(avoid + tok, " \t\r\n");
529 avoid[firstspace] = 0;
531 if(parse_move(&avoid_mv[num_avoid], best+start) != 1)
533 output("Error, could not parse move %s in pos %d\n", best+start, done);
534 return 0;
539 /* get the id */
540 tmp = strstr(buf, "id");
541 if(tmp)
542 sscanf ( tmp, "id %63[^;];", name);
543 else
544 strcpy( name, "<unknown>" );
546 if(!quiet)
548 output(" %d - Thinking", done);
549 if(num_best)
551 output(", the best move%s\e[32;1m", num_best>1 ? "s are" : " is");
552 for(int i=0;i<num_best;i++)
553 output(" %s", move_to_alg(buf, &best_mv[i]) );
554 output("\e[0m");
556 if(num_avoid)
558 output(", the move%s to avoid\e[31;1m", num_avoid>1 ? "s are" : " is");
559 for(int i=0;i<num_avoid;i++)
560 output(" %s", move_to_alg(buf, &avoid_mv[i]) );
561 output("\e[0m");
563 output("\n");
566 if(!strcmp(prog, "self"))
568 st_computer_color = board.color_to_move;
569 m = find_best_move();
571 else
573 fprintf(out, "force\n");
574 board.write_board(buf);
575 fprintf(out, "setboard %s\n", buf);
576 fprintf(out, "st %d\n", time);
577 //fprintf(out, "level 1 %d 0\n", time);
578 fprintf(out, "time %d\n", time*200);
579 fprintf(out, "otim %d\n", time*200);
580 fprintf(out, "go\n");
582 while(fgets(buf, 1024, in))
584 char mv[32];
585 if(!strncmp(buf, "move ", 5))
587 sscanf ( buf, "move %s", mv);
588 if(parse_move( &m, mv )!=1)
590 output("Got illegal move %s\n", mv);
591 return 0;
593 break;
595 else
596 output(buf);
600 bool fail = false;
601 if(!quiet)
602 output("Result: \e[36;1m%s\e[0m\n", move_to_alg(buf, &m));
603 for(int i=0;i<num_avoid;i++)
604 if(m == avoid_mv[i])
606 fail = true;
607 if(!quiet)
608 output("Test %d \e[31;1mFAILURE\e[0m, %s did not avoid the "
609 "wrong move \e[33;1m%s\e[0m (che pollo!)\n",done, prog,
610 move_to_alg(buf, &avoid_mv[i]));
612 if(num_avoid && !fail && !quiet)
613 output("Test %d \e[32;1mSUCCESS\e[0m, %s avoided the "
614 "wrong move%s \e[33;1m%s\e[0m (teto figo!)\n",
615 done, prog, num_avoid>1?"s":"", avoid);
616 if(!fail && num_best)
618 fail = true;
619 for(int i=0;i<num_best;i++)
620 if(m == best_mv[i])
622 fail = false;
623 if(!quiet)
624 output("Test %d \e[32;1mSUCCESS\e[0m, %s found the "
625 "best move \e[33;1m%s\e[0m (o se figo!)\n",
626 done, prog, move_to_alg(buf, &best_mv[i]));
627 break;
629 if(fail && !quiet)
630 output("Test %d \e[31;1mFAILURE\e[0m, %s missed the best "
631 "move%s (\e[33;1m%s\e[0m) (che scarso!)\n", done, prog,
632 num_best>1?"s":"", best);
634 if(!fail)
635 passed++;
636 else
637 failed[done] = true;
639 if(!quiet)
640 output("Test %d %s %s! (+%d, -%d, ~%d%%)\n", done, name, fail ?
641 "\e[31;1mFAILED\e[0m" : "\e[32;1mPASSED\e[0m",
642 passed, done-passed, passed*100/done);
643 else
644 output("%s", fail ? "-" : "+");
646 if(quiet)
647 output("\n");
648 output("Passed %d tests out of %d (%d%%)\n", passed, done, passed*100/done);
649 if(!quiet)
651 output("Failed are:\n");
652 int numsh = 0;
653 for(int i=1;i<done+1;i++)
654 if(failed[i])
656 output(" %d", i);
657 if(((++numsh) % 10) == 0)
658 output("\n");
660 output("\n");
663 if(strcmp(prog, "self"))
665 fprintf(out, "quit\n");
666 fclose(out);
667 fclose(in);
669 fclose(f);
671 return passed;
674 void Engine::save_pgn(FILE *f, const char *result1, const char *result)
676 for(int i=mv_done_num-1;i>=0;i--)
677 board.undo_move(mv_done[i]);
679 fprintf(f, "[White \"%s\"]\n", st_computer_color == WHITE ?
680 "RattateChess" : opponent );
681 fprintf(f, "[Black \"%s\"]\n", st_computer_color == BLACK ?
682 "RattateChess" : opponent );
683 fprintf(f, "[WhiteELO \"%d\"]\n", w_rating);
684 fprintf(f, "[BlackELO \"%d\"]\n", b_rating);
686 time_t t = time(NULL);
687 char tbuf[256];
688 strftime(tbuf, 256, "%Y.%m.%d %H:%M", localtime(&t));
689 fprintf(f, "[Date \"%s\"]\n", tbuf);
690 fprintf(f, "[Result \"%s\"]\n", result1);
692 if(0)
694 char fen[256];
695 board.write_board(fen);
696 fprintf(f, "[FEN \"%s\"]\n", fen);
699 if(board.color_to_move==BLACK)
700 fprintf(f, "%d. ... ",board.num_moves+1);
701 for(int i=0;i<mv_done_num;i++)
703 char buf[32];
704 if(board.color_to_move==WHITE)
705 fprintf(f, "%d. ",board.num_moves+1);
706 fprintf(f, "%s ", move_to_alg(buf, &mv_done[i]) );
707 if((i+1)%14 == 0 && i!=mv_done_num-1)
708 fprintf(f, "\n");
709 board.do_move(mv_done[i]);
711 fprintf(f, "\n%s\n\n", result);
714 void Engine::challenge(const char* prog, int time, const char* file)
716 char buf[1024];
717 FILE *in = NULL;
718 FILE *out = NULL;
719 FILE *f;
720 FILE *log;
721 int won=0, draw=0, lost=0;
723 /* open the file with the tests */
724 f = fopen(file, "r");
725 log = fopen("challenge.pgn", "w");
727 if(!f)
729 output("Error, could not open %s for reading!\n", file);
730 return;
733 start_engine(prog, &in, &out);
735 while(fgets(buf, 1024, f))
737 uint8_t cols[2] = {WHITE, BLACK};
739 for(int i=0;i<2;i++)
741 char fen[256];
742 bool go_done = false;
743 read_board(buf);
744 //set_max_nodes(time);
745 set_time_fixed(time);
746 ponder = false;
747 board.write_board(fen);
749 fprintf(out, "new\n");
750 fprintf(out, "st %d\n", time);
751 //fprintf(out, "level 1 %d 0\n", time);
752 fprintf(out, "force\n");
753 fprintf(out, "setboard %s\n", fen);
756 status = PLAYING;
757 st_computer_color = cols[i];
759 while(1)
761 char buf[1024];
763 /*output("\n\n");
764 board.print_board();*/
766 /* print the pgn to the log file */
767 if(status != PLAYING)
769 const char *result = status==_01?"0-1":(status==_10?"1-0":"1/2-1/2");
770 const char *white = st_computer_color == WHITE ? "Rattatechess" : prog;
771 const char *black = st_computer_color == BLACK ? "Rattatechess" : prog;
773 if(log)
775 for(int i=mv_done_num-1;i>=0;i--)
776 board.undo_move(mv_done[i]);
778 fprintf(log, "[White \"%s\"]\n", white);
779 fprintf(log, "[Black \"%s\"]\n", black);
780 fprintf(log, "[Result \"%s\"]\n", result);
781 fprintf(log, "[FEN \"%s\"]\n", fen);
783 if(board.color_to_move==BLACK)
784 fprintf(log, "%d. ... ",board.num_moves+1);
785 for(int i=0;i<mv_done_num;i++)
787 char buf[32];
788 if(board.color_to_move==WHITE)
789 fprintf(log, "%d. ",board.num_moves+1);
790 fprintf(log, "%s ", move_to_alg(buf, &mv_done[i]) );
791 if((i+1)%14 == 0)
792 fprintf(log, "\n");
793 board.do_move(mv_done[i]);
795 fprintf(log, "%s\n\n", result);
796 fflush(log);
799 if((status==_01 && st_computer_color==BLACK) ||
800 (status==_10 && st_computer_color==WHITE))
802 output("RATTA!!!\n");
803 won++;
805 else if(status==_12)
807 output("DRAW!\n");
808 draw++;
810 else
812 output("ARGH!!!\n");
813 lost++;
815 break;
818 /* think or wait for a new move */
819 if(st_computer_color == board.color_to_move)
821 char buf2[32];
823 /* think and move */
824 Move mv = find_best_move();
825 output("%d. %s %s\n",board.num_moves+1,
826 board.color_to_move==BLACK ? "..." : "",
827 move_to_alg(buf2, &mv) );
828 fprintf( out, "%s\n", move_to_coord(buf2,&mv));
829 move(mv);
831 else
833 if(!go_done)
835 fprintf( out, "go\n");
836 go_done = true;
839 while(fgets(buf, 1024, in))
841 /* get a move from the other engine */
842 if(!strncmp(buf, "move ", 5))
844 Move mv;
845 char buf2[32];
846 sscanf( buf, "move %s", buf2);
847 if(parse_move( &mv, buf2 )!=1)
849 output("Got illegal move %s\n", buf2);
850 return;
852 output("%d. %s %s\n",board.num_moves+1,
853 board.color_to_move==BLACK ? "..." : "",
854 move_to_alg(buf2, &mv) );
855 move(mv);
856 break;
858 else if(!strcmp(buf, "resign"))
860 status = board.color_to_move==WHITE?_01:_10;
861 break;
863 //else
864 // output(buf);
871 fprintf(out, "quit\n");
872 fclose(out);
873 fclose(in);
874 if(log) fclose(log);
875 fclose(f);
877 output("\n\n%d games played (+%d =%d -%d)\n", won+draw+lost, won, draw, lost);