15 #include "move_gen.h"
\r
16 #include "move_legal.h"
\r
24 static const bool UseSlowDebug = false;
\r
35 static bool san_to_lan (const char san[], const board_t * board, char string[], int size);
\r
36 static int move_from_lan (const char string[], const board_t * board);
\r
38 static int ambiguity (int move, const board_t * board);
\r
42 bool move_to_san(int move, const board_t * board, char string[], int size) {
\r
44 int from, to, piece;
\r
45 char tmp_string[256];
\r
47 ASSERT(move_is_ok(move));
\r
48 ASSERT(board_is_ok(board));
\r
49 ASSERT(string!=NULL);
\r
52 ASSERT(move_is_legal(move,board));
\r
54 if (size < 8) return false;
\r
58 from = move_from(move);
\r
65 if (move_is_castle(move,board)) {
\r
68 strcat(string,"O-O");
\r
70 strcat(string,"O-O-O");
\r
78 piece = board->square[from];
\r
80 if (piece_is_pawn(piece)) {
\r
84 if (move_is_capture(move,board)) {
\r
85 sprintf(tmp_string,"%c",file_to_char(square_file(from)));
\r
86 strcat(string,tmp_string);
\r
93 sprintf(tmp_string,"%c",toupper(piece_to_char(piece)));
\r
94 strcat(string,tmp_string);
\r
98 switch (ambiguity(move,board)) {
\r
99 case AMBIGUITY_NONE:
\r
101 case AMBIGUITY_FILE:
\r
102 sprintf(tmp_string,"%c",file_to_char(square_file(from)));
\r
103 strcat(string,tmp_string);
\r
105 case AMBIGUITY_RANK:
\r
106 sprintf(tmp_string,"%c",rank_to_char(square_rank(from)));
\r
107 strcat(string,tmp_string);
\r
109 case AMBIGUITY_SQUARE:
\r
110 if (!square_to_string(from,tmp_string,256)) return false;
\r
111 strcat(string,tmp_string);
\r
121 if (move_is_capture(move,board)) strcat(string,"x");
\r
125 if (!square_to_string(to,tmp_string,256)) return false;
\r
126 strcat(string,tmp_string);
\r
130 if (move_is_promote(move)) {
\r
131 sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board))));
\r
132 strcat(string,tmp_string);
\r
139 if (move_is_mate(move,board)) {
\r
140 strcat(string,"#");
\r
141 } else if (move_is_check(move,board)) {
\r
142 strcat(string,"+");
\r
150 int move_from_san(const char string[], const board_t * board) {
\r
155 ASSERT(string!=NULL);
\r
156 ASSERT(board_is_ok(board));
\r
158 san_to_lan(string,board,s,256);
\r
159 move = move_from_lan(s,board);
\r
161 ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));
\r
166 // move_from_san_debug()
\r
168 int move_from_san_debug(const char string[], const board_t * board) {
\r
172 char move_string[256];
\r
174 ASSERT(string!=NULL);
\r
175 ASSERT(board_is_ok(board));
\r
177 gen_legal_moves(list,board);
\r
179 for (i = 0; i < list_size(list); i++) {
\r
180 move = list_move(list,i);
\r
181 if (!move_to_san(move,board,move_string,256)) ASSERT(false);
\r
182 if (my_string_equal(move_string,string)) return move;
\r
190 static bool san_to_lan(const char san[], const board_t * board, char string[], int size) {
\r
196 char king_string[3], rook_string[3];
\r
199 ASSERT(board_is_ok(board));
\r
200 ASSERT(string!=NULL);
\r
205 if (size < 8) return false;
\r
206 strcpy(string,"???????");
\r
213 // skip trailing '+' or '#'
\r
215 if (left < right) {
\r
217 if (c == '+' || c == '#') right--;
\r
226 } else if (right == 3 && strncmp(san,"O-O",3) == 0) {
\r
228 if (board->castle[board->turn][SideH] == SquareNone) return false;
\r
230 king = king_pos(board,board->turn);
\r
231 rook = board->castle[board->turn][SideH];
\r
233 square_to_string(king,king_string,3);
\r
234 square_to_string(rook,rook_string,3);
\r
236 sprintf(string,"K%s?%s?",king_string,rook_string);
\r
238 } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) {
\r
240 if (board->castle[board->turn][SideA] == SquareNone) return false;
\r
242 king = king_pos(board,board->turn);
\r
243 rook = board->castle[board->turn][SideA];
\r
245 square_to_string(king,king_string,3);
\r
246 square_to_string(rook,rook_string,3);
\r
248 sprintf(string,"K%s?%s?",king_string,rook_string);
\r
254 if (left < right) {
\r
258 if (char_is_piece(c)) {
\r
266 if (left < right) {
\r
268 c = toupper(san[right-1]);
\r
270 if (char_is_piece(c)) {
\r
277 if (left < right && san[right-1] == '=') right--;
\r
283 if (left < right) {
\r
287 if (char_is_rank(c)) {
\r
295 if (left < right) {
\r
299 if (char_is_file(c)) {
\r
307 if (left < right) {
\r
311 if (char_is_piece(c)) {
\r
317 // skip middle '-' or 'x'
\r
319 if (left < right) {
\r
321 if (c == '-' || c == 'x') right--;
\r
324 // from-square file
\r
326 if (left < right) {
\r
330 if (char_is_file(c)) {
\r
336 // from-square rank
\r
338 if (left < right) {
\r
342 if (char_is_rank(c)) {
\r
348 if (left != right) return false;
\r
358 static int move_from_lan(const char string[], const board_t * board) {
\r
373 ASSERT(string!=NULL);
\r
374 ASSERT(board_is_ok(board));
\r
378 len = strlen(string);
\r
379 if (len != 7) return MoveNone;
\r
382 colour = board->turn;
\r
388 switch (string[6]) {
\r
389 case '?': // not a promotion
\r
392 promote = MovePromoteKnight;
\r
395 promote = MovePromoteBishop;
\r
398 promote = MovePromoteRook;
\r
401 promote = MovePromoteQueen;
\r
414 to = square_from_string(s);
\r
415 if (to == SquareNone) return MoveNone;
\r
417 // known from square?
\r
419 if (string[1] != '?' && string[2] != '?') {
\r
427 from = square_from_string(s);
\r
428 if (from == SquareNone) return MoveNone;
\r
430 // convert "king slide" castling to KxR
\r
432 if (piece_is_king(board->square[from])
\r
433 && square_rank(to) == square_rank(from)
\r
434 && abs(to-from) > 1) {
\r
435 side = (to > from) ? SideH : SideA;
\r
436 to = board->castle[colour][side];
\r
437 if (to == SquareNone) return MoveNone;
\r
442 move = move_make(from,to) | promote;
\r
447 // pawn non-capture?
\r
449 if (string[0] == '?' && string[1] == '?') {
\r
451 if (board->square[to] != Empty) return MoveNone; // useful?
\r
453 inc = (colour_is_white(colour)) ? +16 : -16;
\r
456 if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) {
\r
460 if (board->square[from] != piece_make_pawn(colour)) { // useful?
\r
466 move = move_make(from,to) | promote;
\r
473 piece_char = string[0];
\r
475 if (piece_char == '?' && string[1] != '?') {
\r
483 for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {
\r
485 piece = board->square[from];
\r
487 if (toupper(piece_to_char(piece)) == piece_char) {
\r
488 if (piece_attack(board,piece,from,to)) {
\r
490 && (string[1] == '?' || file_to_char(square_file(from)) == string[1])
\r
491 && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) {
\r
492 if (!is_pinned(board,from,to,colour)) {
\r
493 move = move_make(from,to) | promote;
\r
501 if (n != 1) move = MoveNone;
\r
508 static int ambiguity(int move, const board_t * board) {
\r
510 int from, to, piece;
\r
516 from = move_from(move);
\r
517 to = move_to(move);
\r
518 piece = move_piece(move,board);
\r
520 gen_legal_moves(list,board);
\r
526 for (i = 0; i < list_size(list); i++) {
\r
527 m = list_move(list,i);
\r
528 if (move_piece(m,board) == piece && move_to(m) == to) {
\r
533 if (n == 1) return AMBIGUITY_NONE;
\r
539 for (i = 0; i < list_size(list); i++) {
\r
540 m = list_move(list,i);
\r
541 if (move_piece(m,board) == piece && move_to(m) == to) {
\r
542 if (square_file(move_from(m)) == square_file(from)) n++;
\r
546 if (n == 1) return AMBIGUITY_FILE;
\r
552 for (i = 0; i < list_size(list); i++) {
\r
553 m = list_move(list,i);
\r
554 if (move_piece(m,board) == piece && move_to(m) == to) {
\r
555 if (square_rank(move_from(m)) == square_rank(from)) n++;
\r
559 if (n == 1) return AMBIGUITY_RANK;
\r
561 // square ambiguity
\r
563 return AMBIGUITY_SQUARE;
\r