-\r
-// san.c\r
-\r
-// includes\r
-\r
-#include <ctype.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "attack.h"\r
-#include "board.h"\r
-#include "list.h"\r
-#include "move.h"\r
-#include "move_gen.h"\r
-#include "move_legal.h"\r
-#include "piece.h"\r
-#include "san.h"\r
-#include "square.h"\r
-#include "util.h"\r
-\r
-// constants\r
-\r
-static const bool UseSlowDebug = FALSE;\r
-\r
-enum ambiguity_t {\r
- AMBIGUITY_NONE,\r
- AMBIGUITY_FILE,\r
- AMBIGUITY_RANK,\r
- AMBIGUITY_SQUARE\r
-};\r
-\r
-// functions\r
-\r
-static bool san_to_lan (const char san[], const board_t * board, char string[], int size);\r
-static int move_from_lan (const char string[], const board_t * board);\r
-\r
-static int ambiguity (int move, const board_t * board);\r
-\r
-// move_to_san()\r
-\r
-bool move_to_san(int move, const board_t * board, char string[], int size) {\r
-\r
- int from, to, piece;\r
- char tmp_string[256];\r
-\r
- ASSERT(move_is_ok(move));\r
- ASSERT(board_is_ok(board));\r
- ASSERT(string!=NULL);\r
- ASSERT(size>=8);\r
-\r
- ASSERT(move_is_legal(move,board));\r
-\r
- if (size < 8) return FALSE;\r
-\r
- // init\r
-\r
- from = move_from(move);\r
- to = move_to(move);\r
-\r
- string[0] = '\0';\r
-\r
- // castle\r
-\r
- if (move_is_castle(move,board)) {\r
-\r
- if (to > from) {\r
- strcat(string,"O-O");\r
- } else {\r
- strcat(string,"O-O-O");\r
- }\r
-\r
- goto check;\r
- }\r
-\r
- // from\r
-\r
- piece = board->square[from];\r
-\r
- if (piece_is_pawn(piece)) {\r
-\r
- // pawn\r
-\r
- if (move_is_capture(move,board)) {\r
- sprintf(tmp_string,"%c",file_to_char(square_file(from)));\r
- strcat(string,tmp_string);\r
- }\r
-\r
- } else {\r
-\r
- // piece\r
-\r
- sprintf(tmp_string,"%c",toupper(piece_to_char(piece)));\r
- strcat(string,tmp_string);\r
-\r
- // ambiguity\r
-\r
- switch (ambiguity(move,board)) {\r
- case AMBIGUITY_NONE:\r
- break;\r
- case AMBIGUITY_FILE:\r
- sprintf(tmp_string,"%c",file_to_char(square_file(from)));\r
- strcat(string,tmp_string);\r
- break;\r
- case AMBIGUITY_RANK:\r
- sprintf(tmp_string,"%c",rank_to_char(square_rank(from)));\r
- strcat(string,tmp_string);\r
- break;\r
- case AMBIGUITY_SQUARE:\r
- if (!square_to_string(from,tmp_string,256)) return FALSE;\r
- strcat(string,tmp_string);\r
- break;\r
- default:\r
- ASSERT(FALSE);\r
- break;\r
- }\r
- }\r
-\r
- // capture\r
-\r
- if (move_is_capture(move,board)) strcat(string,"x");\r
-\r
- // to\r
-\r
- if (!square_to_string(to,tmp_string,256)) return FALSE;\r
- strcat(string,tmp_string);\r
-\r
- // promote\r
-\r
- if (move_is_promote(move)) {\r
- sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board))));\r
- strcat(string,tmp_string);\r
- }\r
-\r
- // check\r
-\r
-check:\r
-\r
- if (move_is_mate(move,board)) {\r
- strcat(string,"#");\r
- } else if (move_is_check(move,board)) {\r
- strcat(string,"+");\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-// move_from_san()\r
-\r
-int move_from_san(const char string[], const board_t * board) {\r
-\r
- char s[256];\r
- int move;\r
-\r
- ASSERT(string!=NULL);\r
- ASSERT(board_is_ok(board));\r
-\r
- san_to_lan(string,board,s,256);\r
- move = move_from_lan(s,board);\r
-\r
- ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));\r
-\r
- return move;\r
-}\r
-\r
-// move_from_san_debug()\r
-\r
-int move_from_san_debug(const char string[], const board_t * board) {\r
-\r
- list_t list[1];\r
- int i, move;\r
- char move_string[256];\r
-\r
- ASSERT(string!=NULL);\r
- ASSERT(board_is_ok(board));\r
-\r
- gen_legal_moves(list,board);\r
-\r
- for (i = 0; i < list_size(list); i++) {\r
- move = list_move(list,i);\r
- if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);\r
- if (my_string_equal(move_string,string)) return move;\r
- }\r
-\r
- return MoveNone;\r
-}\r
-\r
-// san_to_lan()\r
-\r
-static bool san_to_lan(const char san[], const board_t * board, char string[], int size) {\r
-\r
- int len;\r
- int left, right;\r
- int c;\r
- int king, rook;\r
- char king_string[3], rook_string[3];\r
-\r
- ASSERT(san!=NULL);\r
- ASSERT(board_is_ok(board));\r
- ASSERT(string!=NULL);\r
- ASSERT(size>=8);\r
-\r
- // init\r
-\r
- if (size < 8) return FALSE;\r
- strcpy(string,"???????");\r
-\r
- len = strlen(san);\r
-\r
- left = 0;\r
- right = len;\r
-\r
- // skip trailing '+' or '#'\r
-\r
- if (left < right) {\r
- c = san[right-1];\r
- if (c == '+' || c == '#') right--;\r
- }\r
-\r
- // castling\r
-\r
- ASSERT(left==0);\r
-\r
- if (FALSE) {\r
-\r
- } else if (right == 3 && strncmp(san,"O-O",3) == 0) {\r
-\r
- if (board->castle[board->turn][SideH] == SquareNone) return FALSE;\r
-\r
- king = king_pos(board,board->turn);\r
- rook = board->castle[board->turn][SideH];\r
-\r
- square_to_string(king,king_string,3);\r
- square_to_string(rook,rook_string,3);\r
-\r
- sprintf(string,"K%s?%s?",king_string,rook_string);\r
-\r
- } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) {\r
-\r
- if (board->castle[board->turn][SideA] == SquareNone) return FALSE;\r
-\r
- king = king_pos(board,board->turn);\r
- rook = board->castle[board->turn][SideA];\r
-\r
- square_to_string(king,king_string,3);\r
- square_to_string(rook,rook_string,3);\r
-\r
- sprintf(string,"K%s?%s?",king_string,rook_string);\r
-\r
- } else {\r
-\r
- // moved piece\r
-\r
- if (left < right) {\r
-\r
- c = san[left];\r
-\r
- if (char_is_piece(c)) {\r
- string[0] = c;\r
- left++;\r
- }\r
- }\r
-\r
- // promotion\r
-\r
- if (left < right) {\r
-\r
- c = toupper(san[right-1]);\r
-\r
- if (char_is_piece(c)) {\r
-\r
- string[6] = c;\r
- right--;\r
-\r
- // skip '='\r
-\r
- if (left < right && san[right-1] == '=') right--;\r
- }\r
- }\r
-\r
- // to-square rank\r
-\r
- if (left < right) {\r
-\r
- c = san[right-1];\r
-\r
- if (char_is_rank(c)) {\r
- string[5] = c;\r
- right--;\r
- }\r
- }\r
-\r
- // to-square file\r
-\r
- if (left < right) {\r
-\r
- c = san[right-1];\r
-\r
- if (char_is_file(c)) {\r
- string[4] = c;\r
- right--;\r
- }\r
- }\r
-\r
- // captured piece\r
-\r
- if (left < right) {\r
-\r
- c = san[right-1];\r
-\r
- if (char_is_piece(c)) {\r
- string[3] = c;\r
- right--;\r
- }\r
- }\r
-\r
- // skip middle '-' or 'x'\r
-\r
- if (left < right) {\r
- c = san[right-1];\r
- if (c == '-' || c == 'x') right--;\r
- }\r
-\r
- // from-square file\r
-\r
- if (left < right) {\r
-\r
- c = san[left];\r
-\r
- if (char_is_file(c)) {\r
- string[1] = c;\r
- left++;\r
- }\r
- }\r
-\r
- // from-square rank\r
-\r
- if (left < right) {\r
-\r
- c = san[left];\r
-\r
- if (char_is_rank(c)) {\r
- string[2] = c;\r
- left++;\r
- }\r
- }\r
-\r
- if (left != right) return FALSE;\r
- }\r
-\r
- // end\r
-\r
- return TRUE;\r
-}\r
-\r
-// move_from_lan()\r
-\r
-static int move_from_lan(const char string[], const board_t * board) {\r
-\r
- int len;\r
- int move;\r
- int promote;\r
- char s[256];\r
- int from, to;\r
- int colour;\r
- int inc;\r
- int piece_char;\r
- int n;\r
- const uint8 * ptr;\r
- int piece;\r
- int side;\r
-\r
- ASSERT(string!=NULL);\r
- ASSERT(board_is_ok(board));\r
-\r
- // init\r
-\r
- len = strlen(string);\r
- if (len != 7) return MoveNone;\r
-\r
- move = MoveNone;\r
- colour = board->turn;\r
-\r
- // promote\r
-\r
- promote = 0;\r
-\r
- switch (string[6]) {\r
- case '?': // not a promotion\r
- break;\r
- case 'N':\r
- promote = MovePromoteKnight;\r
- break;\r
- case 'B':\r
- promote = MovePromoteBishop;\r
- break;\r
- case 'R':\r
- promote = MovePromoteRook;\r
- break;\r
- case 'Q':\r
- promote = MovePromoteQueen;\r
- break;\r
- default:\r
- return MoveNone;\r
- break;\r
- }\r
-\r
- // to square\r
-\r
- s[0] = string[4];\r
- s[1] = string[5];\r
- s[2] = '\0';\r
-\r
- to = square_from_string(s);\r
- if (to == SquareNone) return MoveNone;\r
-\r
- // known from square?\r
-\r
- if (string[1] != '?' && string[2] != '?') {\r
-\r
- // from square\r
-\r
- s[0] = string[1];\r
- s[1] = string[2];\r
- s[2] = '\0';\r
-\r
- from = square_from_string(s);\r
- if (from == SquareNone) return MoveNone;\r
-\r
- // convert "king slide" castling to KxR\r
-\r
- if (piece_is_king(board->square[from])\r
- && square_rank(to) == square_rank(from)\r
- && abs(to-from) > 1) {\r
- side = (to > from) ? SideH : SideA;\r
- to = board->castle[colour][side];\r
- if (to == SquareNone) return MoveNone;\r
- }\r
-\r
- // move\r
-\r
- move = move_make(from,to) | promote;\r
-\r
- return move;\r
- }\r
-\r
- // pawn non-capture?\r
-\r
- if (string[0] == '?' && string[1] == '?') {\r
-\r
- if (board->square[to] != Empty) return MoveNone; // useful?\r
-\r
- inc = (colour_is_white(colour)) ? +16 : -16;\r
-\r
- from = to - inc;\r
- if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) {\r
- from -= inc;\r
- }\r
-\r
- if (board->square[from] != piece_make_pawn(colour)) { // useful?\r
- return MoveNone;\r
- }\r
-\r
- // move\r
-\r
- move = move_make(from,to) | promote;\r
-\r
- return move;\r
- }\r
-\r
- // pawn capture?\r
-\r
- piece_char = string[0];\r
-\r
- if (piece_char == '?' && string[1] != '?') {\r
- piece_char = 'P';\r
- }\r
-\r
- // attack loop\r
-\r
- n = 0;\r
-\r
- for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {\r
-\r
- piece = board->square[from];\r
-\r
- if (toupper(piece_to_char(piece)) == piece_char) {\r
- if (piece_attack(board,piece,from,to)) {\r
- if (TRUE\r
- && (string[1] == '?' || file_to_char(square_file(from)) == string[1])\r
- && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) {\r
- if (!is_pinned(board,from,to,colour)) {\r
- move = move_make(from,to) | promote;\r
- n++;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- if (n != 1) move = MoveNone;\r
-\r
- return move;\r
-}\r
-\r
-// ambiguity()\r
-\r
-static int ambiguity(int move, const board_t * board) {\r
-\r
- int from, to, piece;\r
- list_t list[1];\r
- int i, n, m;\r
-\r
- // init\r
-\r
- from = move_from(move);\r
- to = move_to(move);\r
- piece = move_piece(move,board);\r
-\r
- gen_legal_moves(list,board);\r
-\r
- // no ambiguity?\r
-\r
- n = 0;\r
-\r
- for (i = 0; i < list_size(list); i++) {\r
- m = list_move(list,i);\r
- if (move_piece(m,board) == piece && move_to(m) == to) {\r
- n++;\r
- }\r
- }\r
-\r
- if (n == 1) return AMBIGUITY_NONE;\r
-\r
- // file ambiguity?\r
-\r
- n = 0;\r
-\r
- for (i = 0; i < list_size(list); i++) {\r
- m = list_move(list,i);\r
- if (move_piece(m,board) == piece && move_to(m) == to) {\r
- if (square_file(move_from(m)) == square_file(from)) n++;\r
- }\r
- }\r
-\r
- if (n == 1) return AMBIGUITY_FILE;\r
-\r
- // rank ambiguity?\r
-\r
- n = 0;\r
-\r
- for (i = 0; i < list_size(list); i++) {\r
- m = list_move(list,i);\r
- if (move_piece(m,board) == piece && move_to(m) == to) {\r
- if (square_rank(move_from(m)) == square_rank(from)) n++;\r
- }\r
- }\r
-\r
- if (n == 1) return AMBIGUITY_RANK;\r
-\r
- // square ambiguity\r
-\r
- return AMBIGUITY_SQUARE;\r
-}\r
-\r
-// end of san.cpp\r
-\r
+
+// san.c
+
+// includes
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attack.h"
+#include "board.h"
+#include "list.h"
+#include "move.h"
+#include "move_gen.h"
+#include "move_legal.h"
+#include "piece.h"
+#include "san.h"
+#include "square.h"
+#include "util.h"
+
+// constants
+
+static const bool UseSlowDebug = FALSE;
+
+enum ambiguity_t {
+ AMBIGUITY_NONE,
+ AMBIGUITY_FILE,
+ AMBIGUITY_RANK,
+ AMBIGUITY_SQUARE
+};
+
+// functions
+
+static bool san_to_lan (const char san[], const board_t * board, char string[], int size);
+static int move_from_lan (const char string[], const board_t * board);
+
+static int ambiguity (int move, const board_t * board);
+
+// move_to_san()
+
+bool move_to_san(int move, const board_t * board, char string[], int size) {
+
+ int from, to, piece;
+ char tmp_string[256];
+
+ ASSERT(move_is_ok(move));
+ ASSERT(board_is_ok(board));
+ ASSERT(string!=NULL);
+ ASSERT(size>=8);
+
+ ASSERT(move_is_legal(move,board));
+
+ if (size < 8) return FALSE;
+
+ // init
+
+ from = move_from(move);
+ to = move_to(move);
+
+ string[0] = '\0';
+
+ // castle
+
+ if (move_is_castle(move,board)) {
+
+ if (to > from) {
+ strcat(string,"O-O");
+ } else {
+ strcat(string,"O-O-O");
+ }
+
+ goto check;
+ }
+
+ // from
+
+ piece = board->square[from];
+
+ if (piece_is_pawn(piece)) {
+
+ // pawn
+
+ if (move_is_capture(move,board)) {
+ sprintf(tmp_string,"%c",file_to_char(square_file(from)));
+ strcat(string,tmp_string);
+ }
+
+ } else {
+
+ // piece
+
+ sprintf(tmp_string,"%c",toupper(piece_to_char(piece)));
+ strcat(string,tmp_string);
+
+ // ambiguity
+
+ switch (ambiguity(move,board)) {
+ case AMBIGUITY_NONE:
+ break;
+ case AMBIGUITY_FILE:
+ sprintf(tmp_string,"%c",file_to_char(square_file(from)));
+ strcat(string,tmp_string);
+ break;
+ case AMBIGUITY_RANK:
+ sprintf(tmp_string,"%c",rank_to_char(square_rank(from)));
+ strcat(string,tmp_string);
+ break;
+ case AMBIGUITY_SQUARE:
+ if (!square_to_string(from,tmp_string,256)) return FALSE;
+ strcat(string,tmp_string);
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ // capture
+
+ if (move_is_capture(move,board)) strcat(string,"x");
+
+ // to
+
+ if (!square_to_string(to,tmp_string,256)) return FALSE;
+ strcat(string,tmp_string);
+
+ // promote
+
+ if (move_is_promote(move)) {
+ sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board))));
+ strcat(string,tmp_string);
+ }
+
+ // check
+
+check:
+
+ if (move_is_mate(move,board)) {
+ strcat(string,"#");
+ } else if (move_is_check(move,board)) {
+ strcat(string,"+");
+ }
+
+ return TRUE;
+}
+
+// move_from_san()
+
+int move_from_san(const char string[], const board_t * board) {
+
+ char s[256];
+ int move;
+
+ ASSERT(string!=NULL);
+ ASSERT(board_is_ok(board));
+
+ san_to_lan(string,board,s,256);
+ move = move_from_lan(s,board);
+
+ ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));
+
+ return move;
+}
+
+// move_from_san_debug()
+
+int move_from_san_debug(const char string[], const board_t * board) {
+
+ list_t list[1];
+ int i, move;
+ char move_string[256];
+
+ ASSERT(string!=NULL);
+ ASSERT(board_is_ok(board));
+
+ gen_legal_moves(list,board);
+
+ for (i = 0; i < list_size(list); i++) {
+ move = list_move(list,i);
+ if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);
+ if (my_string_equal(move_string,string)) return move;
+ }
+
+ return MoveNone;
+}
+
+// san_to_lan()
+
+static bool san_to_lan(const char san[], const board_t * board, char string[], int size) {
+
+ int len;
+ int left, right;
+ int c;
+ int king, rook;
+ char king_string[3], rook_string[3];
+
+ ASSERT(san!=NULL);
+ ASSERT(board_is_ok(board));
+ ASSERT(string!=NULL);
+ ASSERT(size>=8);
+
+ // init
+
+ if (size < 8) return FALSE;
+ strcpy(string,"???????");
+
+ len = strlen(san);
+
+ left = 0;
+ right = len;
+
+ // skip trailing '+' or '#'
+
+ if (left < right) {
+ c = san[right-1];
+ if (c == '+' || c == '#') right--;
+ }
+
+ // castling
+
+ ASSERT(left==0);
+
+ if (FALSE) {
+
+ } else if (right == 3 && strncmp(san,"O-O",3) == 0) {
+
+ if (board->castle[board->turn][SideH] == SquareNone) return FALSE;
+
+ king = king_pos(board,board->turn);
+ rook = board->castle[board->turn][SideH];
+
+ square_to_string(king,king_string,3);
+ square_to_string(rook,rook_string,3);
+
+ sprintf(string,"K%s?%s?",king_string,rook_string);
+
+ } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) {
+
+ if (board->castle[board->turn][SideA] == SquareNone) return FALSE;
+
+ king = king_pos(board,board->turn);
+ rook = board->castle[board->turn][SideA];
+
+ square_to_string(king,king_string,3);
+ square_to_string(rook,rook_string,3);
+
+ sprintf(string,"K%s?%s?",king_string,rook_string);
+
+ } else {
+
+ // moved piece
+
+ if (left < right) {
+
+ c = san[left];
+
+ if (char_is_piece(c)) {
+ string[0] = c;
+ left++;
+ }
+ }
+
+ // promotion
+
+ if (left < right) {
+
+ c = toupper(san[right-1]);
+
+ if (char_is_piece(c)) {
+
+ string[6] = c;
+ right--;
+
+ // skip '='
+
+ if (left < right && san[right-1] == '=') right--;
+ }
+ }
+
+ // to-square rank
+
+ if (left < right) {
+
+ c = san[right-1];
+
+ if (char_is_rank(c)) {
+ string[5] = c;
+ right--;
+ }
+ }
+
+ // to-square file
+
+ if (left < right) {
+
+ c = san[right-1];
+
+ if (char_is_file(c)) {
+ string[4] = c;
+ right--;
+ }
+ }
+
+ // captured piece
+
+ if (left < right) {
+
+ c = san[right-1];
+
+ if (char_is_piece(c)) {
+ string[3] = c;
+ right--;
+ }
+ }
+
+ // skip middle '-' or 'x'
+
+ if (left < right) {
+ c = san[right-1];
+ if (c == '-' || c == 'x') right--;
+ }
+
+ // from-square file
+
+ if (left < right) {
+
+ c = san[left];
+
+ if (char_is_file(c)) {
+ string[1] = c;
+ left++;
+ }
+ }
+
+ // from-square rank
+
+ if (left < right) {
+
+ c = san[left];
+
+ if (char_is_rank(c)) {
+ string[2] = c;
+ left++;
+ }
+ }
+
+ if (left != right) return FALSE;
+ }
+
+ // end
+
+ return TRUE;
+}
+
+// move_from_lan()
+
+static int move_from_lan(const char string[], const board_t * board) {
+
+ int len;
+ int move;
+ int promote;
+ char s[256];
+ int from, to;
+ int colour;
+ int inc;
+ int piece_char;
+ int n;
+ const uint8 * ptr;
+ int piece;
+ int side;
+
+ ASSERT(string!=NULL);
+ ASSERT(board_is_ok(board));
+
+ // init
+
+ len = strlen(string);
+ if (len != 7) return MoveNone;
+
+ move = MoveNone;
+ colour = board->turn;
+
+ // promote
+
+ promote = 0;
+
+ switch (string[6]) {
+ case '?': // not a promotion
+ break;
+ case 'N':
+ promote = MovePromoteKnight;
+ break;
+ case 'B':
+ promote = MovePromoteBishop;
+ break;
+ case 'R':
+ promote = MovePromoteRook;
+ break;
+ case 'Q':
+ promote = MovePromoteQueen;
+ break;
+ default:
+ return MoveNone;
+ break;
+ }
+
+ // to square
+
+ s[0] = string[4];
+ s[1] = string[5];
+ s[2] = '\0';
+
+ to = square_from_string(s);
+ if (to == SquareNone) return MoveNone;
+
+ // known from square?
+
+ if (string[1] != '?' && string[2] != '?') {
+
+ // from square
+
+ s[0] = string[1];
+ s[1] = string[2];
+ s[2] = '\0';
+
+ from = square_from_string(s);
+ if (from == SquareNone) return MoveNone;
+
+ // convert "king slide" castling to KxR
+
+ if (piece_is_king(board->square[from])
+ && square_rank(to) == square_rank(from)
+ && abs(to-from) > 1) {
+ side = (to > from) ? SideH : SideA;
+ to = board->castle[colour][side];
+ if (to == SquareNone) return MoveNone;
+ }
+
+ // move
+
+ move = move_make(from,to) | promote;
+
+ return move;
+ }
+
+ // pawn non-capture?
+
+ if (string[0] == '?' && string[1] == '?') {
+
+ if (board->square[to] != Empty) return MoveNone; // useful?
+
+ inc = (colour_is_white(colour)) ? +16 : -16;
+
+ from = to - inc;
+ if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) {
+ from -= inc;
+ }
+
+ if (board->square[from] != piece_make_pawn(colour)) { // useful?
+ return MoveNone;
+ }
+
+ // move
+
+ move = move_make(from,to) | promote;
+
+ return move;
+ }
+
+ // pawn capture?
+
+ piece_char = string[0];
+
+ if (piece_char == '?' && string[1] != '?') {
+ piece_char = 'P';
+ }
+
+ // attack loop
+
+ n = 0;
+
+ for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {
+
+ piece = board->square[from];
+
+ if (toupper(piece_to_char(piece)) == piece_char) {
+ if (piece_attack(board,piece,from,to)) {
+ if (TRUE
+ && (string[1] == '?' || file_to_char(square_file(from)) == string[1])
+ && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) {
+ if (!is_pinned(board,from,to,colour)) {
+ move = move_make(from,to) | promote;
+ n++;
+ }
+ }
+ }
+ }
+ }
+
+ if (n != 1) move = MoveNone;
+
+ return move;
+}
+
+// ambiguity()
+
+static int ambiguity(int move, const board_t * board) {
+
+ int from, to, piece;
+ list_t list[1];
+ int i, n, m;
+
+ // init
+
+ from = move_from(move);
+ to = move_to(move);
+ piece = move_piece(move,board);
+
+ gen_legal_moves(list,board);
+
+ // no ambiguity?
+
+ n = 0;
+
+ for (i = 0; i < list_size(list); i++) {
+ m = list_move(list,i);
+ if (move_piece(m,board) == piece && move_to(m) == to) {
+ n++;
+ }
+ }
+
+ if (n == 1) return AMBIGUITY_NONE;
+
+ // file ambiguity?
+
+ n = 0;
+
+ for (i = 0; i < list_size(list); i++) {
+ m = list_move(list,i);
+ if (move_piece(m,board) == piece && move_to(m) == to) {
+ if (square_file(move_from(m)) == square_file(from)) n++;
+ }
+ }
+
+ if (n == 1) return AMBIGUITY_FILE;
+
+ // rank ambiguity?
+
+ n = 0;
+
+ for (i = 0; i < list_size(list); i++) {
+ m = list_move(list,i);
+ if (move_piece(m,board) == piece && move_to(m) == to) {
+ if (square_rank(move_from(m)) == square_rank(from)) n++;
+ }
+ }
+
+ if (n == 1) return AMBIGUITY_RANK;
+
+ // square ambiguity
+
+ return AMBIGUITY_SQUARE;
+}
+
+// end of san.cpp
+