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 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
) )
140 output("Illegal move (ambiguous): %s\n", s
);
153 output("Illegal move: %s\n", s
);
164 for(int i
=comment_1
; i
<comment_2
; i
++)
173 //converts a move to the dummy notation (e2e4,g7h8q,...)
174 char* Engine::move_to_coord(char* string
,Move
* mv
)
177 *(str
++) = 'a' + X(mv
->from
);
178 *(str
++) = '1' + Y(mv
->from
);
179 *(str
++) = 'a' + X(mv
->to
);
180 *(str
++) = '1' + Y(mv
->to
);
183 if(mv
->flags
> PROMOTE0
)
184 *(str
++) = Board::piecename
[ mv
->flags
-PROMOTE0
]^0x20;
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
)
196 if(mv
->flags
==CASTLEKINGSIDE
)
202 else if(mv
->flags
==CASTLEQUEENSIDE
)
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 */
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?
233 if(X(moves
[i
].from
)==X(mv
->from
))
235 if(Y(moves
[i
].from
)==Y(mv
->from
))
242 if(!samecol
|| samerow
)
243 *(str
++)='a' + X(mv
->from
);
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
);
255 *(str
++)='a' + X(mv
->to
);
256 *(str
++)='1' + Y(mv
->to
);
258 if(mv
->flags
> PROMOTE0
)
261 *(str
++) = Board::piecename
[ mv
->flags
-PROMOTE0
];
264 /* is this move a check(mate)? */
266 if(board
.under_attack( board
.king_pos
[IS_WHITE(board
.color_to_move
)],
270 int n
= board
.find_moves(mv_tmp
);
277 board
.undo_move(*mv
);
282 void Engine::print_moves(Move
* m
,int num
,bool nums
)
285 if(board
.color_to_move
==BLACK
&&nums
)
286 output("%d. ...",board
.num_moves
+1);
294 if(board
.color_to_move
==WHITE
&& nums
)
295 printf(" %d.",board
.num_moves
+1);
296 output( " %s", move_to_alg(str
,m
+i
) );
304 HashEntry
*h
= probe_hash( board
.hash
);
305 if(!h
|| !h
->best_mv
)
308 /* don't follow the hash if there is draw for repetition :) */
310 prev_depth
= h
->depth
;
311 //if(h->depth > prev_depth)
318 hash_mv
[j
] = board
.uncompress_move( h
->best_mv
);
320 /* rerity taht the move in the hash is a legal move */
322 int num_tmp
= board
.find_moves(tmp
);
324 for(int q
=0;q
<num_tmp
;q
++)
325 if(tmp
[q
] == hash_mv
[j
])
334 printf("QUEEEEEEEEEEEEEEE2!!!!!!!!!!\n");
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
]);
347 board
.undo_move(hash_mv
[j
]);
350 board
.undo_move(m
[i
]);
355 /* TODO: load correctly the pgn that start with a fen */
356 int Engine::load_pgn(FILE *f
)
360 board
.set_as_default();
365 if(!fgets(buf
, 1024, f
))
367 if(buf
[0]=='\n' || buf
[0]=='\r' || buf
[0]=='\t'
368 || buf
[0]==' ' || buf
[0]=='[' || buf
[0]=='#')
376 ptr
+= strspn(ptr
, ". \t\r\n");
383 char *tmp
= (ptr
+= strcspn(ptr
, ". \t\r\n"));
384 ptr
+= strspn(ptr
, ". \t\r\n");
387 /* is this the result? */
388 if(!strcmp(t
, "1-0"))
393 else if(!strcmp(t
, "0-1"))
398 else if(!strcmp(t
, "1/2-1/2") || !strcmp(t
, "*"))
404 /* is this a move number? */
411 int retv
= parse_move(&mv
, t
);
415 output("Error! \"%s\" %d\n", t
, retv
);
416 return 0; /* error */
419 mv_done
[mv_done_num
++] = mv
;
423 if(!fgets(buf
, 1024, f
))
428 int Engine::run_epd_prog(const char* prog
, int time
, const char* file
, bool quiet
)
436 /* open the file with the tests */
437 f
= fopen(file
, "r");
440 output("Error, could not open %s for reading!\n", file
);
444 if(!strcmp(prog
, "self"))
448 set_time_fixed(time
);
451 start_engine(prog
, &in
, &out
);
453 /* reset passed flags */
456 for(int i
=0;i
<8000;i
++)
459 while(fgets(buf
, 1024, f
))
462 char color
[2],castle
[5],passing
[3];
465 char name
[64];// = "unknown";
475 sscanf(buf
,"%s%s%s%s",
476 brd
,color
,castle
,passing
);
477 read_board(brd
,color
,castle
,passing
,0,0);
487 /* save the best moves in the best_mv array */
488 tmp
= strstr(buf
, "bm");
492 sscanf(tmp
, "bm %63[^;];", best
);
493 tok
+= strspn(best
+ tok
, " \t\r\n");
495 for(num_best
=0;num_best
<10;num_best
++)
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
);
513 /* save the avoid moves in the best_mv array */
514 tmp
= strstr(buf
, "am");
518 sscanf(tmp
, "am %63[^;];", avoid
);
519 tok
+= strspn(avoid
+ tok
, " \t\r\n");
521 for(num_avoid
=0;num_avoid
<10;num_avoid
++)
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
);
540 tmp
= strstr(buf
, "id");
542 sscanf ( tmp
, "id %63[^;];", name
);
544 strcpy( name
, "<unknown>" );
548 output(" %d - Thinking", done
);
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
]) );
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
]) );
566 if(!strcmp(prog
, "self"))
568 st_computer_color
= board
.color_to_move
;
569 m
= find_best_move();
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
))
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
);
602 output("Result: \e[36;1m%s\e[0m\n", move_to_alg(buf
, &m
));
603 for(int i
=0;i
<num_avoid
;i
++)
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
)
619 for(int i
=0;i
<num_best
;i
++)
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
]));
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
);
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
);
644 output("%s", fail
? "-" : "+");
648 output("Passed %d tests out of %d (%d%%)\n", passed
, done
, passed
*100/done
);
651 output("Failed are:\n");
653 for(int i
=1;i
<done
+1;i
++)
657 if(((++numsh
) % 10) == 0)
663 if(strcmp(prog
, "self"))
665 fprintf(out
, "quit\n");
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
);
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
);
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
++)
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)
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
)
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");
729 output("Error, could not open %s for reading!\n", file
);
733 start_engine(prog
, &in
, &out
);
735 while(fgets(buf
, 1024, f
))
737 uint8_t cols
[2] = {WHITE
, BLACK
};
742 bool go_done
= false;
744 //set_max_nodes(time);
745 set_time_fixed(time
);
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
);
757 st_computer_color
= cols
[i
];
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
;
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
++)
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
]) );
793 board
.do_move(mv_done
[i
]);
795 fprintf(log
, "%s\n\n", result
);
799 if((status
==_01
&& st_computer_color
==BLACK
) ||
800 (status
==_10
&& st_computer_color
==WHITE
))
802 output("RATTA!!!\n");
818 /* think or wait for a new move */
819 if(st_computer_color
== board
.color_to_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
));
835 fprintf( out
, "go\n");
839 while(fgets(buf
, 1024, in
))
841 /* get a move from the other engine */
842 if(!strncmp(buf
, "move ", 5))
846 sscanf( buf
, "move %s", buf2
);
847 if(parse_move( &mv
, buf2
)!=1)
849 output("Got illegal move %s\n", buf2
);
852 output("%d. %s %s\n",board
.num_moves
+1,
853 board
.color_to_move
==BLACK
? "..." : "",
854 move_to_alg(buf2
, &mv
) );
858 else if(!strcmp(buf
, "resign"))
860 status
= board
.color_to_move
==WHITE
?_01
:_10
;
871 fprintf(out
, "quit\n");
877 output("\n\n%d games played (+%d =%d -%d)\n", won
+draw
+lost
, won
, draw
, lost
);