15
#include "move_legal.h"
23
static const bool UseSlowDebug = false;
34
static bool san_to_lan (const char san[], const board_t * board, char string[], int size);
35
static int move_from_lan (const char string[], const board_t * board);
37
static int ambiguity (int move, const board_t * board);
41
bool move_to_san(int move, const board_t * board, char string[], int size) {
46
ASSERT(move_is_ok(move));
47
ASSERT(board_is_ok(board));
51
ASSERT(move_is_legal(move,board));
53
if (size < 8) return false;
57
from = move_from(move);
64
if (move_is_castle(move,board)) {
66
switch (square_file(to)) {
71
strcat(string,"O-O-O");
84
piece = board->square[from];
86
if (piece_is_pawn(piece)) {
90
if (move_is_capture(move,board)) {
91
sprintf(tmp_string,"%c",file_to_char(square_file(from)));
92
strcat(string,tmp_string);
99
sprintf(tmp_string,"%c",toupper(piece_to_char(piece)));
100
strcat(string,tmp_string);
104
switch (ambiguity(move,board)) {
105
case AMBIGUITY_NONE :
107
case AMBIGUITY_FILE :
108
sprintf(tmp_string,"%c",file_to_char(square_file(from)));
109
strcat(string,tmp_string);
111
case AMBIGUITY_RANK :
112
sprintf(tmp_string,"%c",rank_to_char(square_rank(from)));
113
strcat(string,tmp_string);
115
case AMBIGUITY_SQUARE :
116
if (!square_to_string(from,tmp_string,256)) return false;
117
strcat(string,tmp_string);
127
if (move_is_capture(move,board)) strcat(string,"x");
131
if (!square_to_string(to,tmp_string,256)) return false;
132
strcat(string,tmp_string);
136
if (move_is_promote(move)) {
137
sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board))));
138
strcat(string,tmp_string);
145
if (move_is_mate(move,board)) {
147
} else if (move_is_check(move,board)) {
156
int move_from_san(const char string[], const board_t * board) {
161
ASSERT(string!=NULL);
162
ASSERT(board_is_ok(board));
164
san_to_lan(string,board,s,256);
165
move = move_from_lan(s,board);
167
ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));
172
// move_from_san_debug()
174
int move_from_san_debug(const char string[], const board_t * board) {
178
char move_string[256];
180
ASSERT(string!=NULL);
181
ASSERT(board_is_ok(board));
183
gen_legal_moves(list,board);
185
for (i = 0; i < list_size(list); i++) {
186
move = list_move(list,i);
187
if (!move_to_san(move,board,move_string,256)) ASSERT(false);
188
if (my_string_equal(move_string,string)) return move;
196
static bool san_to_lan(const char san[], const board_t * board, char string[], int size) {
203
ASSERT(board_is_ok(board));
204
ASSERT(string!=NULL);
209
if (size < 8) return false;
210
strcpy(string,"???????");
217
// skip trailing '+' or '#'
221
if (c == '+' || c == '#') right--;
230
} else if (right == 3 && strncmp(san,"O-O",3) == 0) {
232
if (colour_is_white(board->turn)) {
233
strcpy(string,"Ke1?g1?");
235
strcpy(string,"Ke8?g8?");
238
} else if (right == 5 && strncmp(san,"O-O-O",5) == 0) {
240
if (colour_is_white(board->turn)) {
241
strcpy(string,"Ke1?c1?");
243
strcpy(string,"Ke8?c8?");
254
if (char_is_piece(c)) {
264
c = toupper(san[right-1]);
266
if (char_is_piece(c)) {
273
if (left < right && san[right-1] == '=') right--;
283
if (char_is_rank(c)) {
295
if (char_is_file(c)) {
307
if (char_is_piece(c)) {
313
// skip middle '-' or 'x'
317
if (c == '-' || c == 'x') right--;
326
if (char_is_file(c)) {
338
if (char_is_rank(c)) {
344
if (left != right) return false;
354
static int move_from_lan(const char string[], const board_t * board) {
368
ASSERT(string!=NULL);
369
ASSERT(board_is_ok(board));
373
len = strlen(string);
374
if (len != 7) return MoveNone;
377
colour = board->turn;
384
case '?': // not a promotion
387
promote = MovePromoteKnight;
390
promote = MovePromoteBishop;
393
promote = MovePromoteRook;
396
promote = MovePromoteQueen;
409
to = square_from_string(s);
410
if (to == SquareNone) return MoveNone;
412
// known from square?
414
if (string[1] != '?' && string[2] != '?') {
422
from = square_from_string(s);
423
if (from == SquareNone) return MoveNone;
427
move = move_make(from,to) | promote;
434
if (string[0] == '?' && string[1] == '?') {
436
if (board->square[to] != Empty) return MoveNone; // useful?
438
inc = (colour_is_white(colour)) ? +16 : -16;
441
if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) {
445
if (board->square[from] != piece_make_pawn(colour)) { // useful?
451
move = move_make(from,to) | promote;
458
piece_char = string[0];
460
if (piece_char == '?' && string[1] != '?') {
468
for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {
470
piece = board->square[from];
472
if (toupper(piece_to_char(piece)) == piece_char) {
473
if (piece_attack(board,piece,from,to)) {
475
&& (string[1] == '?' || file_to_char(square_file(from)) == string[1])
476
&& (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) {
477
if (!is_pinned(board,from,to,colour)) {
478
move = move_make(from,to) | promote;
486
if (n != 1) move = MoveNone;
493
static int ambiguity(int move, const board_t * board) {
501
from = move_from(move);
503
piece = move_piece(move,board);
505
gen_legal_moves(list,board);
511
for (i = 0; i < list_size(list); i++) {
512
m = list_move(list,i);
513
if (move_piece(m,board) == piece && move_to(m) == to) {
518
if (n == 1) return AMBIGUITY_NONE;
524
for (i = 0; i < list_size(list); i++) {
525
m = list_move(list,i);
526
if (move_piece(m,board) == piece && move_to(m) == to) {
527
if (square_file(move_from(m)) == square_file(from)) n++;
531
if (n == 1) return AMBIGUITY_FILE;
537
for (i = 0; i < list_size(list); i++) {
538
m = list_move(list,i);
539
if (move_piece(m,board) == piece && move_to(m) == to) {
540
if (square_rank(move_from(m)) == square_rank(from)) n++;
544
if (n == 1) return AMBIGUITY_RANK;
548
return AMBIGUITY_SQUARE;