X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fposition.cpp;h=326720b0184cde110dfdd9a6d28004bf3f936d82;hb=fe26967ea042b318c26ef6bb600a733d049e2171;hp=4c925f5bba16fc51b8f2417668d0159e47ee450e;hpb=45ce92b89c9191f1606d82611620587157956e1b;p=stockfish diff --git a/src/position.cpp b/src/position.cpp index 4c925f5b..326720b0 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -77,33 +76,8 @@ namespace { // Bonus for having the side to move (modified by Joona Kiiski) const Score TempoValue = make_score(48, 22); - struct PieceLetters : public std::map { - - PieceLetters() { - - operator[]('K') = WK; operator[]('k') = BK; - operator[]('Q') = WQ; operator[]('q') = BQ; - operator[]('R') = WR; operator[]('r') = BR; - operator[]('B') = WB; operator[]('b') = BB; - operator[]('N') = WN; operator[]('n') = BN; - operator[]('P') = WP; operator[]('p') = BP; - operator[](' ') = PIECE_NONE; - operator[]('.') = PIECE_NONE_DARK_SQ; - } - - char from_piece(Piece p) const { - - std::map::const_iterator it; - for (it = begin(); it != end(); ++it) - if (it->second == p) - return it->first; - - assert(false); - return 0; - } - }; - - PieceLetters pieceLetters; + // To convert a Piece to and from a FEN char + const string PieceToChar(".PNBRQK pnbrqk "); } @@ -113,16 +87,17 @@ CheckInfo::CheckInfo(const Position& pos) { Color us = pos.side_to_move(); Color them = opposite_color(us); + Square ksq = pos.king_square(them); - ksq = pos.king_square(them); dcCandidates = pos.discovered_check_candidates(us); + pinned = pos.pinned_pieces(us); - checkSq[PAWN] = pos.attacks_from(ksq, them); + checkSq[PAWN] = pos.attacks_from(ksq, them); checkSq[KNIGHT] = pos.attacks_from(ksq); checkSq[BISHOP] = pos.attacks_from(ksq); - checkSq[ROOK] = pos.attacks_from(ksq); - checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK]; - checkSq[KING] = EmptyBoardBB; + checkSq[ROOK] = pos.attacks_from(ksq); + checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK]; + checkSq[KING] = EmptyBoardBB; } @@ -192,17 +167,19 @@ void Position::from_fen(const string& fen, bool isChess960) { char token; int hmc, fmn; - std::istringstream ss(fen); + size_t p; Square sq = SQ_A8; + std::istringstream ss(fen); clear(); + ss >> std::noskipws; // 1. Piece placement field - while (ss.get(token) && token != ' ') + while ((ss >> token) && !isspace(token)) { - if (pieceLetters.find(token) != pieceLetters.end()) + if ((p = PieceToChar.find(token)) != string::npos) { - put_piece(pieceLetters[token], sq); + put_piece(Piece(p), sq); sq++; } else if (isdigit(token)) @@ -214,25 +191,25 @@ void Position::from_fen(const string& fen, bool isChess960) { } // 2. Active color - if (!ss.get(token) || (token != 'w' && token != 'b')) + if (!(ss >> token) || (token != 'w' && token != 'b')) goto incorrect_fen; sideToMove = (token == 'w' ? WHITE : BLACK); - if (!ss.get(token) || token != ' ') + if (!(ss >> token) || !isspace(token)) goto incorrect_fen; // 3. Castling availability - while (ss.get(token) && token != ' ') + while ((ss >> token) && !isspace(token)) if (!set_castling_rights(token)) goto incorrect_fen; // 4. En passant square char col, row; - if ( (ss.get(col) && (col >= 'a' && col <= 'h')) - && (ss.get(row) && (row == '3' || row == '6'))) + if ( ((ss >> col) && (col >= 'a' && col <= 'h')) + && ((ss >> row) && (row == '3' || row == '6'))) { - st->epSquare = make_square(file_from_char(col), rank_from_char(row)); + st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1); // Ignore if no capture is possible Color them = opposite_color(sideToMove); @@ -241,7 +218,7 @@ void Position::from_fen(const string& fen, bool isChess960) { } // 5. Halfmove clock - if (ss >> hmc) + if (ss >> std::skipws >> hmc) st->rule50 = hmc; // 6. Fullmove number @@ -294,7 +271,7 @@ bool Position::set_castling_rights(char token) { for (Square sq = sqH; sq >= sqA; sq--) if (piece_on(sq) == rook) { - do_allow_oo(c); + set_castle_kingside(c); initialKRFile = square_file(sq); break; } @@ -304,7 +281,7 @@ bool Position::set_castling_rights(char token) { for (Square sq = sqA; sq <= sqH; sq++) if (piece_on(sq) == rook) { - do_allow_ooo(c); + set_castle_queenside(c); initialQRFile = square_file(sq); break; } @@ -314,12 +291,12 @@ bool Position::set_castling_rights(char token) { File rookFile = File(token - 'A') + FILE_A; if (rookFile < initialKFile) { - do_allow_ooo(c); + set_castle_queenside(c); initialQRFile = rookFile; } else { - do_allow_oo(c); + set_castle_kingside(c); initialKRFile = rookFile; } } @@ -337,10 +314,12 @@ const string Position::to_fen() const { string fen; Square sq; - char emptyCnt = '0'; + char emptyCnt; for (Rank rank = RANK_8; rank >= RANK_1; rank--, fen += '/') { + emptyCnt = '0'; + for (File file = FILE_A; file <= FILE_H; file++) { sq = make_square(file, rank); @@ -352,16 +331,13 @@ const string Position::to_fen() const { fen += emptyCnt; emptyCnt = '0'; } - fen += pieceLetters.from_piece(piece_on(sq)); + fen += PieceToChar[piece_on(sq)]; } else emptyCnt++; } if (emptyCnt != '0') - { fen += emptyCnt; - emptyCnt = '0'; - } } fen += (sideToMove == WHITE ? " w " : " b "); @@ -413,7 +389,7 @@ void Position::print(Move move) const { piece = PIECE_NONE_DARK_SQ; char c = (color_of_piece_on(sq) == BLACK ? '=' : ' '); - cout << c << pieceLetters.from_piece(piece) << c << '|'; + cout << c << PieceToChar[piece] << c << '|'; } } cout << dottedLine << "Fen is: " << to_fen() << "\nKey is: " << st->key << endl; @@ -624,16 +600,19 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// Position::move_is_legal() takes a position and a (not necessarily pseudo-legal) -/// move and tests whether the move is legal. This version is not very fast and -/// should be used only in non time-critical paths. +/// Position::move_is_pl_slow() takes a position and a move and tests whether +/// the move is pseudo legal. This version is not very fast and should be used +/// only in non time-critical paths. -bool Position::move_is_pl_full(const Move m) const { +bool Position::move_is_pl_slow(const Move m) const { MoveStack mlist[MAX_MOVES]; - MoveStack *cur, *last = generate(*this, mlist); + MoveStack *cur, *last; - for (cur = mlist; cur != last; cur++) + last = in_check() ? generate(*this, mlist) + : generate(*this, mlist); + + for (cur = mlist; cur != last; cur++) if (cur->move == m) return true; @@ -641,8 +620,8 @@ bool Position::move_is_pl_full(const Move m) const { } -/// Fast version of Position::move_is_legal() that takes a position a move and -/// a bitboard of pinned pieces as input, and tests whether the move is legal. +/// Fast version of Position::move_is_pl() that takes a position a move and a +/// bitboard of pinned pieces as input, and tests whether the move is pseudo legal. bool Position::move_is_pl(const Move m) const { @@ -656,10 +635,10 @@ bool Position::move_is_pl(const Move m) const { // Use a slower but simpler function for uncommon cases if (move_is_special(m)) - return move_is_pl_full(m); + return move_is_pl_slow(m); // Is not a promotion, so promotion piece must be empty - if (move_promotion_piece(m) - 2 != PIECE_TYPE_NONE) + if (promotion_piece_type(m) - 2 != PIECE_TYPE_NONE) return false; // If the from square is not occupied by a piece belonging to the side to @@ -768,18 +747,12 @@ bool Position::move_is_pl(const Move m) const { /// Position::move_gives_check() tests whether a pseudo-legal move is a check -bool Position::move_gives_check(Move m) const { - - return move_gives_check(m, CheckInfo(*this)); -} - bool Position::move_gives_check(Move m, const CheckInfo& ci) const { assert(is_ok()); assert(move_is_ok(m)); assert(ci.dcCandidates == discovered_check_candidates(side_to_move())); assert(color_of_piece_on(move_from(m)) == side_to_move()); - assert(piece_on(ci.ksq) == make_piece(opposite_color(side_to_move()), KING)); Square from = move_from(m); Square to = move_to(m); @@ -794,7 +767,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { { // For pawn and king moves we need to verify also direction if ( (pt != PAWN && pt != KING) - || !squares_aligned(from, to, ci.ksq)) + || !squares_aligned(from, to, king_square(opposite_color(side_to_move())))) return true; } @@ -804,22 +777,23 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { Color us = side_to_move(); Bitboard b = occupied_squares(); + Square ksq = king_square(opposite_color(us)); // Promotion with check ? if (move_is_promotion(m)) { clear_bit(&b, from); - switch (move_promotion_piece(m)) + switch (promotion_piece_type(m)) { case KNIGHT: - return bit_is_set(attacks_from(to), ci.ksq); + return bit_is_set(attacks_from(to), ksq); case BISHOP: - return bit_is_set(bishop_attacks_bb(to, b), ci.ksq); + return bit_is_set(bishop_attacks_bb(to, b), ksq); case ROOK: - return bit_is_set(rook_attacks_bb(to, b), ci.ksq); + return bit_is_set(rook_attacks_bb(to, b), ksq); case QUEEN: - return bit_is_set(queen_attacks_bb(to, b), ci.ksq); + return bit_is_set(queen_attacks_bb(to, b), ksq); default: assert(false); } @@ -835,8 +809,8 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { clear_bit(&b, from); clear_bit(&b, capsq); set_bit(&b, to); - return (rook_attacks_bb(ci.ksq, b) & pieces(ROOK, QUEEN, us)) - ||(bishop_attacks_bb(ci.ksq, b) & pieces(BISHOP, QUEEN, us)); + return (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us)) + ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us)); } // Castling with check ? @@ -858,7 +832,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { clear_bit(&b, rfrom); set_bit(&b, rto); set_bit(&b, kto); - return bit_is_set(rook_attacks_bb(rto, b), ci.ksq); + return bit_is_set(rook_attacks_bb(rto, b), ksq); } return false; @@ -971,13 +945,12 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI st->epSquare = SQ_NONE; } - // Update castle rights, try to shortcut a common case - int cm = castleRightsMask[from] & castleRightsMask[to]; - if (cm != ALL_CASTLES && ((cm & st->castleRights) != st->castleRights)) + // Update castle rights if needed + if ( st->castleRights != CASTLES_NONE + && (castleRightsMask[from] & castleRightsMask[to]) != ALL_CASTLES) { key ^= zobCastle[st->castleRights]; - st->castleRights &= castleRightsMask[from]; - st->castleRights &= castleRightsMask[to]; + st->castleRights &= castleRightsMask[from] & castleRightsMask[to]; key ^= zobCastle[st->castleRights]; } @@ -1020,7 +993,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (pm) // promotion ? { - PieceType promotion = move_promotion_piece(m); + PieceType promotion = promotion_piece_type(m); assert(promotion >= KNIGHT && promotion <= QUEEN); @@ -1089,10 +1062,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from)) { if (pt != ROOK) - st->checkersBB |= (attacks_from(ci.ksq) & pieces(ROOK, QUEEN, us)); + st->checkersBB |= (attacks_from(king_square(them)) & pieces(ROOK, QUEEN, us)); if (pt != BISHOP) - st->checkersBB |= (attacks_from(ci.ksq) & pieces(BISHOP, QUEEN, us)); + st->checkersBB |= (attacks_from(king_square(them)) & pieces(BISHOP, QUEEN, us)); } } } @@ -1300,7 +1273,7 @@ void Position::undo_move(Move m) { if (pm) // promotion ? { - PieceType promotion = move_promotion_piece(m); + PieceType promotion = promotion_piece_type(m); pt = PAWN; assert(promotion >= KNIGHT && promotion <= QUEEN); @@ -1775,7 +1748,7 @@ Value Position::compute_non_pawn_material(Color c) const { /// Position::is_draw() tests whether the position is drawn by material, /// repetition, or the 50 moves rule. It does not detect stalemates, this /// must be done by the search. - +template bool Position::is_draw() const { // Draw by material? @@ -1788,13 +1761,18 @@ bool Position::is_draw() const { return true; // Draw by repetition? - for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2) - if (history[st->gamePly - i] == st->key) - return true; + if (!SkipRepetition) + for (int i = 4, e = Min(Min(st->gamePly, st->rule50), st->pliesFromNull); i <= e; i += 2) + if (history[st->gamePly - i] == st->key) + return true; return false; } +// Explicit template instantiations +template bool Position::is_draw() const; +template bool Position::is_draw() const; + /// Position::is_mate() returns true or false depending on whether the /// side to move is checkmated. @@ -1806,35 +1784,30 @@ bool Position::is_mate() const { } -/// Position::init_zobrist() is a static member function which initializes at -/// startup the various arrays used to compute hash keys. +/// Position::init() is a static member function which initializes at +/// startup the various arrays used to compute hash keys and the piece +/// square tables. The latter is a two-step operation: First, the white +/// halves of the tables are copied from the MgPST[][] and EgPST[][] arrays. +/// Second, the black halves of the tables are initialized by mirroring +/// and changing the sign of the corresponding white scores. -void Position::init_zobrist() { +void Position::init() { - int i,j, k; RKISS rk; - for (i = 0; i < 2; i++) for (j = 0; j < 8; j++) for (k = 0; k < 64; k++) - zobrist[i][j][k] = rk.rand(); + for (Color c = WHITE; c <= BLACK; c++) + for (PieceType pt = PAWN; pt <= KING; pt++) + for (Square s = SQ_A1; s <= SQ_H8; s++) + zobrist[c][pt][s] = rk.rand(); - for (i = 0; i < 64; i++) - zobEp[i] = rk.rand(); + for (Square s = SQ_A1; s <= SQ_H8; s++) + zobEp[s] = rk.rand(); - for (i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) zobCastle[i] = rk.rand(); zobSideToMove = rk.rand(); zobExclusion = rk.rand(); -} - - -/// Position::init_piece_square_tables() initializes the piece square tables. -/// This is a two-step operation: First, the white halves of the tables are -/// copied from the MgPST[][] and EgPST[][] arrays. Second, the black halves -/// of the tables are initialized by mirroring and changing the sign of the -/// corresponding white scores. - -void Position::init_piece_square_tables() { for (Square s = SQ_A1; s <= SQ_H8; s++) for (Piece p = WP; p <= WK; p++) @@ -1868,10 +1841,10 @@ void Position::flip() { sideToMove = opposite_color(pos.side_to_move()); // Castling rights - if (pos.can_castle_kingside(WHITE)) do_allow_oo(BLACK); - if (pos.can_castle_queenside(WHITE)) do_allow_ooo(BLACK); - if (pos.can_castle_kingside(BLACK)) do_allow_oo(WHITE); - if (pos.can_castle_queenside(BLACK)) do_allow_ooo(WHITE); + if (pos.can_castle_kingside(WHITE)) set_castle_kingside(BLACK); + if (pos.can_castle_queenside(WHITE)) set_castle_queenside(BLACK); + if (pos.can_castle_kingside(BLACK)) set_castle_kingside(WHITE); + if (pos.can_castle_queenside(BLACK)) set_castle_queenside(WHITE); initialKFile = pos.initialKFile; initialKRFile = pos.initialKRFile; @@ -1931,7 +1904,7 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) *failedStep = 1; // Side to move OK? - if (!color_is_ok(side_to_move())) + if (side_to_move() != WHITE && side_to_move() != BLACK) return false; // Are the king squares in the position correct? @@ -1945,10 +1918,10 @@ bool Position::is_ok(int* failedStep) const { // Castle files OK? if (failedStep) (*failedStep)++; - if (!file_is_ok(initialKRFile)) + if (!square_is_ok(make_square(initialKRFile, RANK_1))) return false; - if (!file_is_ok(initialQRFile)) + if (!square_is_ok(make_square(initialQRFile, RANK_1))) return false; // Do both sides have exactly one king?