X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsan.cpp;h=1fc8d13cfc5502c48252fb19f40bbdf942d1f818;hb=ee0afea1e57e4c39140c838b9f9f2d5c7c061e6b;hp=545fae8fd5bd6a96ec37acd7786aca70a600ddd7;hpb=aad8c82cf693447d5ea075b5cb5819c8e26d8680;p=stockfish diff --git a/src/san.cpp b/src/san.cpp index 545fae8f..1fc8d13c 100644 --- a/src/san.cpp +++ b/src/san.cpp @@ -28,8 +28,7 @@ #include #include -#include "history.h" -#include "movepick.h" +#include "movegen.h" #include "san.h" using std::string; @@ -41,14 +40,9 @@ using std::string; namespace { enum Ambiguity { - AMBIGUITY_NONE, - AMBIGUITY_FILE, - AMBIGUITY_RANK, - AMBIGUITY_BOTH + AMBIGUITY_NONE, AMBIGUITY_FILE, AMBIGUITY_RANK, AMBIGUITY_BOTH }; - const History H; // Used as dummy argument for MovePicker c'tor - Ambiguity move_ambiguity(const Position& pos, Move m); const string time_string(int milliseconds); const string score_string(Value v); @@ -59,6 +53,52 @@ namespace { //// Functions //// +/// move_to_uci() converts a move to a string in coordinate notation +/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we +/// print in the e1g1 notation in normal chess mode, and in e1h1 notation in +/// Chess960 mode. + +const std::string move_to_uci(Move m, bool chess960) { + + std::string promotion; + Square from = move_from(m); + Square to = move_to(m); + + if (m == MOVE_NONE) + return "(none)"; + + if (m == MOVE_NULL) + return "0000"; + + if (move_is_short_castle(m) && !chess960) + return from == SQ_E1 ? "e1g1" : "e8g8"; + + if (move_is_long_castle(m) && !chess960) + return from == SQ_E1 ? "e1c1" : "e8c8"; + + if (move_is_promotion(m)) + promotion = char(tolower(piece_type_to_char(move_promotion_piece(m)))); + + return square_to_string(from) + square_to_string(to) + promotion; +} + + +/// move_from_uci() takes a position and a string representing a move in +/// simple coordinate notation and returns an equivalent Move. + +Move move_from_uci(const Position& pos, const std::string& str) { + + MoveStack mlist[MOVES_MAX]; + MoveStack* last = generate(pos, mlist); + + for (MoveStack* cur = mlist; cur != last; cur++) + if (str == move_to_uci(cur->move, pos.is_chess960())) + return cur->move; + + return MOVE_NONE; +} + + /// move_to_san() takes a position and a move as input, where it is assumed /// that the move is a legal move from the position. The return value is /// a string containing the move in short algebraic notation. @@ -71,21 +111,23 @@ const string move_to_san(Position& pos, Move m) { string san; Square from = move_from(m); Square to = move_to(m); - PieceType pt = type_of_piece(pos.piece_on(move_from(m))); + PieceType pt = type_of_piece(pos.piece_on(from)); if (m == MOVE_NONE) return "(none)"; - else if (m == MOVE_NULL) + + if (m == MOVE_NULL) return "(null)"; - else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING)) + + if (move_is_long_castle(m)) san = "O-O-O"; - else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING)) + else if (move_is_short_castle(m)) san = "O-O"; else { if (pt != PAWN) { - san += piece_type_to_char(pt, true); + san += piece_type_to_char(pt); switch (move_ambiguity(pos, m)) { case AMBIGUITY_NONE: @@ -103,17 +145,20 @@ const string move_to_san(Position& pos, Move m) { assert(false); } } + if (pos.move_is_capture(m)) { if (pt == PAWN) - san += file_to_char(square_file(move_from(m))); - san += "x"; + san += file_to_char(square_file(from)); + + san += 'x'; } - san += square_to_string(move_to(m)); + san += square_to_string(to); + if (move_is_promotion(m)) { - san += "="; - san += piece_type_to_char(move_promotion_piece(m), true); + san += '='; + san += piece_type_to_char(move_promotion_piece(m)); } } @@ -129,159 +174,6 @@ const string move_to_san(Position& pos, Move m) { } -/// move_from_san() takes a position and a string as input, and tries to -/// interpret the string as a move in short algebraic notation. On success, -/// the move is returned. On failure (i.e. if the string is unparsable, or -/// if the move is illegal or ambiguous), MOVE_NONE is returned. - -Move move_from_san(const Position& pos, const string& movestr) { - - assert(pos.is_ok()); - - MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H); - Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); - - // Castling moves - if (movestr == "O-O-O" || movestr == "O-O-O+") - { - Move m; - while ((m = mp.get_next_move()) != MOVE_NONE) - if (move_is_long_castle(m) && pos.pl_move_is_legal(m, pinned)) - return m; - - return MOVE_NONE; - } - else if (movestr == "O-O" || movestr == "O-O+") - { - Move m; - while ((m = mp.get_next_move()) != MOVE_NONE) - if (move_is_short_castle(m) && pos.pl_move_is_legal(m, pinned)) - return m; - - return MOVE_NONE; - } - - // Normal moves. We use a simple FSM to parse the san string. - enum { START, TO_FILE, TO_RANK, PROMOTION_OR_CHECK, PROMOTION, CHECK, END }; - static const string pieceLetters = "KQRBN"; - PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE; - File fromFile = FILE_NONE, toFile = FILE_NONE; - Rank fromRank = RANK_NONE, toRank = RANK_NONE; - Square to; - int state = START; - - for (size_t i = 0; i < movestr.length(); i++) - { - char type, c = movestr[i]; - if (pieceLetters.find(c) != string::npos) - type = 'P'; - else if (c >= 'a' && c <= 'h') - type = 'F'; - else if (c >= '1' && c <= '8') - type = 'R'; - else - type = c; - - switch (type) { - case 'P': - if (state == START) - { - pt = piece_type_from_char(c); - state = TO_FILE; - } - else if (state == PROMOTION) - { - promotion = piece_type_from_char(c); - state = (i < movestr.length() - 1) ? CHECK : END; - } - else - return MOVE_NONE; - break; - case 'F': - if (state == START) - { - pt = PAWN; - fromFile = toFile = file_from_char(c); - state = TO_RANK; - } - else if (state == TO_FILE) - { - toFile = file_from_char(c); - state = TO_RANK; - } - else if (state == TO_RANK && toFile != FILE_NONE) - { - // Previous file was for disambiguation - fromFile = toFile; - toFile = file_from_char(c); - } - else - return MOVE_NONE; - break; - case 'R': - if (state == TO_RANK) - { - toRank = rank_from_char(c); - state = (i < movestr.length() - 1) ? PROMOTION_OR_CHECK : END; - } - else if (state == TO_FILE && fromRank == RANK_NONE) - { - // It's a disambiguation rank instead of a file - fromRank = rank_from_char(c); - } - else - return MOVE_NONE; - break; - case 'x': case 'X': - if (state == TO_RANK) - { - // Previous file was for disambiguation, or it's a pawn capture - fromFile = toFile; - state = TO_FILE; - } - else if (state != TO_FILE) - return MOVE_NONE; - break; - case '=': - if (state == PROMOTION_OR_CHECK) - state = PROMOTION; - else - return MOVE_NONE; - break; - case '+': case '#': - if (state == PROMOTION_OR_CHECK || state == CHECK) - state = END; - else - return MOVE_NONE; - break; - default: - return MOVE_NONE; - break; - } - } - - if (state != END) - return MOVE_NONE; - - // Look for a matching move - Move m, move = MOVE_NONE; - to = make_square(toFile, toRank); - int matches = 0; - - while ((m = mp.get_next_move()) != MOVE_NONE) - if ( pos.type_of_piece_on(move_from(m)) == pt - && move_to(m) == to - && move_promotion_piece(m) == promotion - && (fromFile == FILE_NONE || fromFile == square_file(move_from(m))) - && (fromRank == RANK_NONE || fromRank == square_rank(move_from(m)))) - { - move = m; - matches++; - } - return (matches == 1 ? move : MOVE_NONE); -} - - /// line_to_san() takes a position and a line (an array of moves representing /// a sequence of legal moves from the position) as input, and returns a /// string containing the line in short algebraic notation. If the boolean @@ -322,11 +214,11 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool /// It is used to write search information to the log file (which is created /// when the UCI parameter "Use Search Log" is "true"). -const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, +const string pretty_pv(const Position& pos, int time, int depth, Value score, ValueType type, Move pv[]) { - const uint64_t K = 1000; - const uint64_t M = 1000000; + const int64_t K = 1000; + const int64_t M = 1000000; std::stringstream s; @@ -341,12 +233,12 @@ const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, s << std::setw(8) << time_string(time) << " "; // Nodes - if (nodes < M) - s << std::setw(8) << nodes / 1 << " "; - else if (nodes < K * M) - s << std::setw(7) << nodes / K << "K "; + if (pos.nodes_searched() < M) + s << std::setw(8) << pos.nodes_searched() / 1 << " "; + else if (pos.nodes_searched() < K * M) + s << std::setw(7) << pos.nodes_searched() / K << "K "; else - s << std::setw(7) << nodes / M << "M "; + s << std::setw(7) << pos.nodes_searched() / M << "M "; // PV s << line_to_san(pos, pv, 30, true); @@ -359,43 +251,36 @@ namespace { Ambiguity move_ambiguity(const Position& pos, Move m) { + MoveStack mlist[MOVES_MAX], *last; + Move candidates[8]; Square from = move_from(m); Square to = move_to(m); Piece pc = pos.piece_on(from); + int matches = 0, f = 0, r = 0; - // King moves are never ambiguous, because there is never two kings of - // the same color. - if (type_of_piece(pc) == KING) + // If there is only one piece 'pc' then move cannot be ambiguous + if (pos.piece_count(pos.side_to_move(), type_of_piece(pc)) == 1) return AMBIGUITY_NONE; - MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H); - Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); - Move mv, moveList[8]; - - int n = 0; - while ((mv = mp.get_next_move()) != MOVE_NONE) - if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv, pinned)) - moveList[n++] = mv; + // Collect all legal moves of piece 'pc' with destination 'to' + last = generate(pos, mlist); + for (MoveStack* cur = mlist; cur != last; cur++) + if (move_to(cur->move) == to && pos.piece_on(move_from(cur->move)) == pc) + candidates[matches++] = cur->move; - if (n == 1) + if (matches == 1) return AMBIGUITY_NONE; - int f = 0, r = 0; - for (int i = 0; i < n; i++) + for (int i = 0; i < matches; i++) { - if (square_file(move_from(moveList[i])) == square_file(from)) + if (square_file(move_from(candidates[i])) == square_file(from)) f++; - if (square_rank(move_from(moveList[i])) == square_rank(from)) + if (square_rank(move_from(candidates[i])) == square_rank(from)) r++; } - if (f == 1) - return AMBIGUITY_FILE; - - if (r == 1) - return AMBIGUITY_RANK; - return AMBIGUITY_BOTH; + return f == 1 ? AMBIGUITY_FILE : r == 1 ? AMBIGUITY_RANK : AMBIGUITY_BOTH; }