1 /***************************************************************************
2 moveparse.cpp - description
4 begin : mer ott 30 2002
5 copyright : (C) 2002-2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
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
)
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
;
41 int Engine::parse_move(Move
* mv
,char* s
)
50 int comment_2
= strlen(s
);
54 if(!strncmp(s
, "0-0-0", 5) || !strncmp(s
, "O-O-O", 5) || !strncmp(s
, "o-o-o", 5) )
59 int num_moves
= board
.find_moves(moves
);
61 for(int i
=0;i
<num_moves
;i
++)
62 if(moves
[i
].flags
== CASTLEQUEENSIDE
)
68 output("Illegal move: %s\n", s
);
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) )
78 int num_moves
= board
.find_moves(moves
);
80 for(int i
=0;i
<num_moves
;i
++)
81 if(moves
[i
].flags
== CASTLEKINGSIDE
)
87 output("Illegal move: %s\n", s
);
92 if(s
[pos
]>='A' && s
[pos
]<='Z' && (piece
=char_to_piece(s
[pos
])) != -1)
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')
100 if(s
[pos
]>='A' && s
[pos
]<='Z' && char_to_piece(s
[pos
]) != -1)
102 if(s
[pos
]>='a' && s
[pos
]<='h')
105 to_x
= s
[pos
++] - 'a';
107 if(s
[pos
]>='1' && s
[pos
]<='8')
110 to_y
= s
[pos
++] - '1';
114 if((promote
=char_to_piece(s
[pos
])) != -1)
117 if(to_x
!= -1 && to_y
!= -1)
119 if(piece
==-1 && (from_x
==-1 || from_y
==-1))
124 /* find a unique matching move */
126 int num_moves
= board
.find_moves(moves
);
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
++)
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
) )
149 output("Illegal move (ambiguous): %s\n", s
);
154 //printf("Found!\n");
163 output("Illegal move: %s\n", s
);
174 for(int i
=comment_1
; i
<comment_2
; i
++)
183 //converts a move to the dummy notation (e2e4,g7h8q,...)
184 char* Engine::move_to_coord(char* string
,Move
* mv
)
187 *(str
++) = 'a' + X(mv
->from
);
188 *(str
++) = '1' + Y(mv
->from
);
189 *(str
++) = 'a' + X(mv
->to
);
190 *(str
++) = '1' + Y(mv
->to
);
193 if(mv
->flags
> PROMOTE0
)
194 *(str
++) = Board::piecename
[ mv
->flags
-PROMOTE0
]^0x20;
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
)
206 if(mv
->flags
==CASTLEKINGSIDE
)
212 else if(mv
->flags
==CASTLEQUEENSIDE
)
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 */
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?
243 if(X(moves
[i
].from
)==X(mv
->from
))
245 if(Y(moves
[i
].from
)==Y(mv
->from
))
252 if(!samecol
|| samerow
)
253 *(str
++)='a' + X(mv
->from
);
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
);
265 *(str
++)='a' + X(mv
->to
);
266 *(str
++)='1' + Y(mv
->to
);
268 if(mv
->flags
> PROMOTE0
)
271 *(str
++) = Board::piecename
[ mv
->flags
-PROMOTE0
];
274 /* is this move a check(mate)? */
276 if(board
.under_attack( board
.king_pos
[IS_WHITE(board
.color_to_move
)],
280 int n
= board
.find_moves(mv_tmp
);
287 board
.undo_move(*mv
);
292 void Engine::print_moves(Move
* m
,int num
,bool nums
)
295 if(board
.color_to_move
==BLACK
&&nums
)
296 output("%d. ...",board
.num_moves
+1);
304 if(board
.color_to_move
==WHITE
&& nums
)
305 printf(" %d.",board
.num_moves
+1);
306 output( " %s", move_to_alg(str
,m
+i
) );
314 HashEntry
*h
= probe_hash( board
.hash
);
315 if(!h
|| !h
->best_mv
)
318 /* don't follow the hash if there is draw for repetition :) */
320 prev_depth
= h
->depth
;
321 //if(h->depth > prev_depth)
328 hash_mv
[j
] = board
.uncompress_move( h
->best_mv
);
330 /* rerity taht the move in the hash is a legal move */
332 int num_tmp
= board
.find_moves(tmp
);
334 for(int q
=0;q
<num_tmp
;q
++)
335 if(tmp
[q
] == hash_mv
[j
])
344 printf("QUEEEEEEEEEEEEEEE2!!!!!!!!!!\n");
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
]);
357 board
.undo_move(hash_mv
[j
]);
360 board
.undo_move(m
[i
]);
365 /* TODO: load correctly the pgn that start with a fen */
366 int Engine::load_pgn(FILE *f
)
370 board
.set_as_default();
375 if(!fgets(buf
, 1024, f
))
377 if(buf
[0]=='\n' || buf
[0]=='\r' || buf
[0]=='\t'
378 || buf
[0]==' ' || buf
[0]=='[' || buf
[0]=='#')
386 ptr
+= strspn(ptr
, ". \t\r\n");
393 char *tmp
= (ptr
+= strcspn(ptr
, ". \t\r\n"));
394 ptr
+= strspn(ptr
, ". \t\r\n");
397 /* is this the result? */
398 if(!strcmp(t
, "1-0"))
403 else if(!strcmp(t
, "0-1"))
408 else if(!strcmp(t
, "1/2-1/2") || !strcmp(t
, "*"))
414 /* is this a move number? */
421 int retv
= parse_move(&mv
, t
);
425 output("Error! \"%s\" %d\n", t
, retv
);
426 return 0; /* error */
429 mv_done
[mv_done_num
++] = mv
;
433 if(!fgets(buf
, 1024, f
))
438 int Engine::run_epd_prog(const char* prog
, int time
, const char* file
, bool quiet
)
446 /* open the file with the tests */
447 f
= fopen(file
, "r");
450 output("Error, could not open %s for reading!\n", file
);
454 if(!strcmp(prog
, "self"))
458 set_time_fixed(time
);
461 start_engine(prog
, &in
, &out
);
463 /* reset passed flags */
466 for(int i
=0;i
<8000;i
++)
469 while(fgets(buf
, 1024, f
))
472 char color
[2],castle
[5],passing
[3];
475 char name
[64];// = "unknown";
485 sscanf(buf
,"%s%s%s%s",
486 brd
,color
,castle
,passing
);
487 read_board(brd
,color
,castle
,passing
,0,0);
496 //printf("%s\n", buf);
498 /* save the best moves in the best_mv array */
499 tmp
= strstr(buf
, "bm");
503 sscanf(tmp
, "bm %63[^;];", best
);
504 tok
+= strspn(best
+ tok
, " \t\r\n");
506 for(num_best
=0;num_best
<10;num_best
++)
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
);
526 /* save the avoid moves in the best_mv array */
527 tmp
= strstr(buf
, "am");
531 sscanf(tmp
, "am %63[^;];", avoid
);
532 tok
+= strspn(avoid
+ tok
, " \t\r\n");
534 for(num_avoid
=0;num_avoid
<10;num_avoid
++)
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
);
555 tmp
= strstr(buf
, "id");
557 sscanf ( tmp
, "id %63[^;];", name
);
559 strcpy( name
, "<unknown>" );
563 output(" %d - Thinking", done
);
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
]) );
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
]) );
581 if(!strcmp(prog
, "self"))
583 st_computer_color
= board
.color_to_move
;
584 m
= find_best_move();
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
))
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
);
617 output("Result: \e[36;1m%s\e[0m\n", move_to_alg(buf
, &m
));
618 for(int i
=0;i
<num_avoid
;i
++)
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
)
634 for(int i
=0;i
<num_best
;i
++)
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
]));
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
);
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
);
659 output("%s", fail
? "-" : "+");
661 snprintf(str
, 40, "(%d/%d)", passed
, done
);
665 fwrite(str
, 2*l
, 1, stdout
);
671 output("Passed %d tests out of %d (%d%%)\n", passed
, done
, passed
*100/done
);
674 output("Failed are:\n");
676 for(int i
=1;i
<done
+1;i
++)
680 if(((++numsh
) % 10) == 0)
686 if(strcmp(prog
, "self"))
688 fprintf(out
, "quit\n");
697 void Engine::save_pgn(FILE *f
, const char *result1
, const char *result
)
699 for(int i
=mv_done_num
-1;i
>=0;i
--)
700 board
.undo_move(mv_done
[i
]);
702 fprintf(f
, "[White \"%s\"]\n", st_computer_color
== WHITE
?
703 "RattateChess" : opponent
);
704 fprintf(f
, "[Black \"%s\"]\n", st_computer_color
== BLACK
?
705 "RattateChess" : opponent
);
706 fprintf(f
, "[WhiteELO \"%d\"]\n", w_rating
);
707 fprintf(f
, "[BlackELO \"%d\"]\n", b_rating
);
709 time_t t
= time(NULL
);
711 strftime(tbuf
, 256, "%Y.%m.%d %H:%M", localtime(&t
));
712 fprintf(f
, "[Date \"%s\"]\n", tbuf
);
713 fprintf(f
, "[Result \"%s\"]\n", result1
);
718 board
.write_board(fen
);
719 fprintf(f
, "[FEN \"%s\"]\n", fen
);
722 if(board
.color_to_move
==BLACK
)
723 fprintf(f
, "%d. ... ",board
.num_moves
+1);
724 for(int i
=0;i
<mv_done_num
;i
++)
727 if(board
.color_to_move
==WHITE
)
728 fprintf(f
, "%d. ",board
.num_moves
+1);
729 fprintf(f
, "%s ", move_to_alg(buf
, &mv_done
[i
]) );
730 if((i
+1)%14 == 0 && i
!=mv_done_num
-1)
732 board
.do_move(mv_done
[i
]);
734 fprintf(f
, "\n%s\n\n", result
);
737 void Engine::challenge(const char* prog
, int time
, const char* file
)
744 int won
=0, draw
=0, lost
=0;
746 /* open the file with the tests */
747 f
= fopen(file
, "r");
748 log
= fopen("challenge.pgn", "w");
752 output("Error, could not open %s for reading!\n", file
);
756 start_engine(prog
, &in
, &out
);
758 while(fgets(buf
, 1024, f
))
760 uint8_t cols
[2] = {WHITE
, BLACK
};
765 bool go_done
= false;
767 //set_max_nodes(time);
768 //set_time_fixed(time);
769 set_time_control(40, time
, 0);
771 board
.write_board(fen
);
773 fprintf(out
, "new\n");
774 //fprintf(out, "st %d\n", time);
775 fprintf(out
, "level 40 %d:%d 0\n", time
/60, time
%60);
776 fprintf(out
, "force\n");
777 fprintf(out
, "setboard %s\n", fen
);
781 st_computer_color
= cols
[i
];
788 board.print_board();*/
790 /* print the pgn to the log file */
791 if(status
!= PLAYING
)
793 const char *result
= status
==_01
?"0-1":(status
==_10
?"1-0":"1/2-1/2");
794 const char *white
= st_computer_color
== WHITE
? "Rattatechess" : prog
;
795 const char *black
= st_computer_color
== BLACK
? "Rattatechess" : prog
;
799 for(int i
=mv_done_num
-1;i
>=0;i
--)
800 board
.undo_move(mv_done
[i
]);
802 fprintf(log
, "[White \"%s\"]\n", white
);
803 fprintf(log
, "[Black \"%s\"]\n", black
);
804 fprintf(log
, "[Result \"%s\"]\n", result
);
805 fprintf(log
, "[FEN \"%s\"]\n", fen
);
807 if(board
.color_to_move
==BLACK
)
808 fprintf(log
, "%d. ... ",board
.num_moves
+1);
809 for(int i
=0;i
<mv_done_num
;i
++)
812 if(board
.color_to_move
==WHITE
)
813 fprintf(log
, "%d. ",board
.num_moves
+1);
814 fprintf(log
, "%s ", move_to_alg(buf
, &mv_done
[i
]) );
817 board
.do_move(mv_done
[i
]);
819 fprintf(log
, "%s\n\n", result
);
823 if((status
==_01
&& st_computer_color
==BLACK
) ||
824 (status
==_10
&& st_computer_color
==WHITE
))
826 output("RATTA!!!\n");
842 /* think or wait for a new move */
843 if(st_computer_color
== board
.color_to_move
)
848 Move mv
= find_best_move();
849 output("%d. %s %s\n",board
.num_moves
+1,
850 board
.color_to_move
==BLACK
? "..." : "",
851 move_to_alg(buf2
, &mv
) );
852 fprintf( out
, "%s\n", move_to_coord(buf2
,&mv
));
859 fprintf( out
, "go\n");
863 while(fgets(buf
, 1024, in
))
865 /* get a move from the other engine */
866 if(!strncmp(buf
, "move ", 5))
870 sscanf( buf
, "move %s", buf2
);
871 if(parse_move( &mv
, buf2
)!=1)
873 output("Got illegal move %s\n", buf2
);
876 output("%d. %s %s\n",board
.num_moves
+1,
877 board
.color_to_move
==BLACK
? "..." : "",
878 move_to_alg(buf2
, &mv
) );
882 else if(!strcmp(buf
, "resign"))
884 status
= board
.color_to_move
==WHITE
?_01
:_10
;
895 fprintf(out
, "quit\n");
901 output("\n\n%d games played (+%d =%d -%d)\n", won
+draw
+lost
, won
, draw
, lost
);