const std::string move_to_san(Position &pos, Move m) { std::string str; assert(pos.is_ok()); assert(move_is_ok(m)); Square from, to; Piece pc; from = move_from(m); to = move_to(m); pc = pos.piece_on(move_from(m)); if(m == MOVE_NONE) { str = "(none)"; return str; } else if(m == MOVE_NULL) { str = "(null)"; return str; } else if(move_is_long_castle(m) || (int(to - from) == -2 && type_of_piece(pc) == KING)) str = "O-O-O"; else if(move_is_short_castle(m) || (int(to - from) == 2 && type_of_piece(pc) == KING)) str = "O-O"; else { str = ""; if(type_of_piece(pc) == PAWN) { if(pos.move_is_capture(m)) str += file_to_char(square_file(move_from(m))); } else { str += piece_type_to_char(type_of_piece(pc), true); Ambiguity amb = move_ambiguity(pos, m); switch(amb) { case AMBIGUITY_NONE: break; case AMBIGUITY_FILE: str += file_to_char(square_file(from)); break; case AMBIGUITY_RANK: str += rank_to_char(square_rank(from)); break; case AMBIGUITY_BOTH: str += square_to_string(from); break; default: assert(false); } } if(pos.move_is_capture(m)) str += "x"; str += square_to_string(move_to(m)); if(move_promotion(m)) { str += "="; str += piece_type_to_char(move_promotion(m), true); } } // Is the move check? We don't use pos.move_is_check(m) here, because // Position::move_is_check doesn't detect all checks (not castling moves, // promotions and en passant captures). UndoInfo u; pos.do_move(m, u); if(pos.is_check()) str += pos.is_mate()? "#" : "+"; pos.undo_move(m, u); return str; }
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; }
bool board_to_fen(const board_t * board, char string[], int size) { int pos; int file, rank; int sq, piece; int c; int len; int old_pos; ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=92); // init if (size < 92) return false; pos = 0; // piece placement for (rank = 7; rank >= 0; rank--) { for (file = 0; file < 8;) { sq = square_make(file,rank); piece = board->square[sq]; ASSERT(piece==Empty||piece_is_ok(piece)); if (piece == Empty) { len = 0; for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) { len++; } ASSERT(len>=1&&len<=8); c = '0' + len; } else { c = piece_to_char(piece); file++; } string[pos++] = c; } string[pos++] = '/'; } string[pos-1] = ' '; // HACK: remove the last '/' // active colour string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b'; string[pos++] = ' '; // castling old_pos = pos; if (option_get_bool("Chess960")) { // FEN-960 if (board->castle[White][SideH] != SquareNone) { string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH]))); } if (board->castle[White][SideA] != SquareNone) { string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA]))); } if (board->castle[Black][SideH] != SquareNone) { string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH]))); } if (board->castle[Black][SideA] != SquareNone) { string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA]))); } } else { // FEN if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K'; if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q'; if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k'; if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q'; } if (pos == old_pos) string[pos++] = '-'; string[pos++] = ' '; // en-passant if (board->ep_square == SquareNone) { string[pos++] = '-'; } else { if (!square_to_string(board->ep_square,&string[pos],3)) return false; pos += 2; } string[pos++] = ' '; // halfmove clock and fullmove number sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1); return true; }
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; }