X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fposition.cpp;h=eda26014c32c49330a57cbdd996102a555011b0d;hb=856a5f3aaaf8b9d53599963decacd4476b55c034;hp=bb5a86f47f35f9b13778b79c8cbc2f655f8120c8;hpb=152a4dc5cd1c5190b607f4b819ad9bd10bcc1baa;p=stockfish diff --git a/src/position.cpp b/src/position.cpp index bb5a86f4..eda26014 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -690,10 +690,10 @@ bool Position::gives_check(Move m, const CheckInfo& ci) const { void Position::do_move(Move m, StateInfo& newSt) { CheckInfo ci(*this); - do_move(m, newSt, ci, gives_check(m, ci)); + do_move(m, newSt, gives_check(m, ci)); } -void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) { +void Position::do_move(Move m, StateInfo& newSt, bool moveIsCheck) { assert(is_ok(m)); assert(&newSt != st); @@ -856,30 +856,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI // Update the key with the final value st->key = k; - // Update checkers bitboard: piece must be already moved due to attacks_from() - st->checkersBB = 0; - - if (moveIsCheck) - { - if (type_of(m) != NORMAL) - st->checkersBB = attackers_to(king_square(them)) & pieces(us); - else - { - // Direct checks - if (ci.checkSq[pt] & to) - st->checkersBB |= to; - - // Discovered checks - if (ci.dcCandidates && (ci.dcCandidates & from)) - { - if (pt != ROOK) - st->checkersBB |= attacks_from(king_square(them)) & pieces(us, QUEEN, ROOK); - - if (pt != BISHOP) - st->checkersBB |= attacks_from(king_square(them)) & pieces(us, QUEEN, BISHOP); - } - } - } + // Calculate checkers bitboard (if move is check) + st->checkersBB = moveIsCheck ? attackers_to(king_square(them)) & pieces(us) : 0; sideToMove = ~sideToMove; @@ -1098,11 +1076,21 @@ Value Position::see(Move m) const { // Locate and remove the next least valuable attacker captured = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); + + // Stop before processing a king capture + if (captured == KING) + { + if (stmAttackers == attackers) + ++slIndex; + + break; + } + stm = ~stm; stmAttackers = attackers & pieces(stm); ++slIndex; - } while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture + } while (stmAttackers); // Having built the swap list, we negamax through it to find the best // achievable score from the point of view of the side to move. @@ -1137,6 +1125,10 @@ bool Position::is_draw() const { /// Position::flip() flips position with the white and black sides reversed. This /// is only useful for debugging e.g. for finding evaluation symmetry bugs. +static char toggle_case(char c) { + return char(islower(c) ? toupper(c) : tolower(c)); +} + void Position::flip() { string f, token; @@ -1154,8 +1146,7 @@ void Position::flip() { ss >> token; // Castling availability f += token + " "; - std::transform(f.begin(), f.end(), f.begin(), - [](char c) { return char(islower(c) ? toupper(c) : tolower(c)); }); + std::transform(f.begin(), f.end(), f.begin(), toggle_case); ss >> token; // En passant square f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3")); @@ -1172,81 +1163,96 @@ void Position::flip() { /// Position::pos_is_ok() performs some consistency checks for the position object. /// This is meant to be helpful when debugging. -bool Position::pos_is_ok(bool fast, int* failedStep) const { +bool Position::pos_is_ok(int* step) const { - enum { Default, King, Bitboards, State, Lists, Castling }; + // Which parts of the position should be verified? + const bool all = false; - for (int step = Default; step <= (fast ? Default : Castling); step++) + const bool testBitboards = all || false; + const bool testState = all || false; + const bool testKingCount = all || false; + const bool testKingCapture = all || false; + const bool testPieceCounts = all || false; + const bool testPieceList = all || false; + const bool testCastlingSquares = all || false; + + if (step) + *step = 1; + + if ( (sideToMove != WHITE && sideToMove != BLACK) + || piece_on(king_square(WHITE)) != W_KING + || piece_on(king_square(BLACK)) != B_KING + || ( ep_square() != SQ_NONE + && relative_rank(sideToMove, ep_square()) != RANK_6)) + return false; + + if (step && ++*step, testBitboards) { - if (failedStep) - *failedStep = step; - - if (step == Default) - if ( (sideToMove != WHITE && sideToMove != BLACK) - || piece_on(king_square(WHITE)) != W_KING - || piece_on(king_square(BLACK)) != B_KING - || ( ep_square() != SQ_NONE - && relative_rank(sideToMove, ep_square()) != RANK_6)) - return false; + // The intersection of the white and black pieces must be empty + if (pieces(WHITE) & pieces(BLACK)) + return false; - if (step == King) - if ( std::count(board, board + SQUARE_NB, W_KING) != 1 - || std::count(board, board + SQUARE_NB, B_KING) != 1 - || attackers_to(king_square(~sideToMove)) & pieces(sideToMove)) - return false; + // The union of the white and black pieces must be equal to all + // occupied squares + if ((pieces(WHITE) | pieces(BLACK)) != pieces()) + return false; - if (step == Bitboards) - { - if ( (pieces(WHITE) & pieces(BLACK)) - ||(pieces(WHITE) | pieces(BLACK)) != pieces()) - return false; + // Separate piece type bitboards must have empty intersections + for (PieceType p1 = PAWN; p1 <= KING; ++p1) + for (PieceType p2 = PAWN; p2 <= KING; ++p2) + if (p1 != p2 && (pieces(p1) & pieces(p2))) + return false; + } - for (PieceType p1 = PAWN; p1 <= KING; ++p1) - for (PieceType p2 = PAWN; p2 <= KING; ++p2) - if (p1 != p2 && (pieces(p1) & pieces(p2))) - return false; - } + if (step && ++*step, testState) + { + StateInfo si; + set_state(&si); + if ( st->key != si.key + || st->pawnKey != si.pawnKey + || st->materialKey != si.materialKey + || st->nonPawnMaterial[WHITE] != si.nonPawnMaterial[WHITE] + || st->nonPawnMaterial[BLACK] != si.nonPawnMaterial[BLACK] + || st->psq != si.psq + || st->checkersBB != si.checkersBB) + return false; + } - if (step == State) - { - StateInfo si; - set_state(&si); - if ( st->key != si.key - || st->pawnKey != si.pawnKey - || st->materialKey != si.materialKey - || st->nonPawnMaterial[WHITE] != si.nonPawnMaterial[WHITE] - || st->nonPawnMaterial[BLACK] != si.nonPawnMaterial[BLACK] - || st->psq != si.psq - || st->checkersBB != si.checkersBB) - return false; - } + if (step && ++*step, testKingCount) + if ( std::count(board, board + SQUARE_NB, W_KING) != 1 + || std::count(board, board + SQUARE_NB, B_KING) != 1) + return false; - if (step == Lists) - for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt = PAWN; pt <= KING; ++pt) - { - if (pieceCount[c][pt] != popcount(pieces(c, pt))) - return false; + if (step && ++*step, testKingCapture) + if (attackers_to(king_square(~sideToMove)) & pieces(sideToMove)) + return false; - for (int i = 0; i < pieceCount[c][pt]; ++i) - if ( board[pieceList[c][pt][i]] != make_piece(c, pt) - || index[pieceList[c][pt][i]] != i) - return false; - } - - if (step == Castling) - for (Color c = WHITE; c <= BLACK; ++c) - for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1)) - { - if (!can_castle(c | s)) - continue; - - if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK) - || castlingRightsMask[castlingRookSquare[c | s]] != (c | s) - ||(castlingRightsMask[king_square(c)] & (c | s)) != (c | s)) + if (step && ++*step, testPieceCounts) + for (Color c = WHITE; c <= BLACK; ++c) + for (PieceType pt = PAWN; pt <= KING; ++pt) + if (pieceCount[c][pt] != popcount(pieces(c, pt))) + return false; + + if (step && ++*step, testPieceList) + for (Color c = WHITE; c <= BLACK; ++c) + for (PieceType pt = PAWN; pt <= KING; ++pt) + for (int i = 0; i < pieceCount[c][pt]; ++i) + if ( board[pieceList[c][pt][i]] != make_piece(c, pt) + || index[pieceList[c][pt][i]] != i) return false; - } - } + + if (step && ++*step, testCastlingSquares) + for (Color c = WHITE; c <= BLACK; ++c) + for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1)) + { + if (!can_castle(c | s)) + continue; + + if ( (castlingRightsMask[king_square(c)] & (c | s)) != (c | s) + || piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK) + || castlingRightsMask[castlingRookSquare[c | s]] != (c | s)) + return false; + } return true; }