X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=d5f28218ea8aa53c53846a02516157edc8e0b2ae;hp=382073a7020dc2a1199cc9e5604b1d8d91c85048;hb=f30aa83f8ad46a794e83f030fdab576371c8c825;hpb=c45818e9f86fea63a6b46d0726cdcfe87516d01b diff --git a/src/position.cpp b/src/position.cpp index 382073a7..d5f28218 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -210,8 +210,8 @@ void Position::from_fen(const std::string& fen) { key = compute_key(); pawnKey = compute_pawn_key(); materialKey = compute_material_key(); - mgValue = compute_mg_value(); - egValue = compute_eg_value(); + mgValue = compute_value(MidGame); + egValue = compute_value(EndGame); npMaterial[WHITE] = compute_non_pawn_material(WHITE); npMaterial[BLACK] = compute_non_pawn_material(BLACK); } @@ -323,29 +323,42 @@ void Position::copy(const Position &pos) { /// king) pieces for the given color. Bitboard Position::pinned_pieces(Color c) const { + if (pinned[c] != ~EmptyBoardBB) + return pinned[c]; + + Bitboard p1, p2; Square ksq = king_square(c); - return hidden_checks(c, ksq) | hidden_checks(c, ksq); + pinned[c] = hidden_checks(c, ksq, p1) | hidden_checks(c, ksq, p2); + pinners[c] = p1 | p2; + return pinned[c]; } +Bitboard Position::pinned_pieces(Color c, Bitboard& p) const { + + if (pinned[c] == ~EmptyBoardBB) + pinned_pieces(c); -/// Position:discovered_check_candidates() returns a bitboard containing all -/// pieces for the given side which are candidates for giving a discovered -/// check. The code is almost the same as the function for finding pinned -/// pieces. + p = pinners[c]; + return pinned[c]; +} Bitboard Position::discovered_check_candidates(Color c) const { + if (dcCandidates[c] != ~EmptyBoardBB) + return dcCandidates[c]; + + Bitboard dummy; Square ksq = king_square(opposite_color(c)); - return hidden_checks(c, ksq) | hidden_checks(c, ksq); + dcCandidates[c] = hidden_checks(c, ksq, dummy) | hidden_checks(c, ksq, dummy); + return dcCandidates[c]; } - /// Position:hidden_checks<>() returns a bitboard of all pinned (against the /// king) pieces for the given color and for the given pinner type. Or, when /// template parameter FindPinned is false, the pinned pieces of opposite color /// that are, indeed, the pieces candidate for a discovery check. template -Bitboard Position::hidden_checks(Color c, Square ksq) const { +Bitboard Position::hidden_checks(Color c, Square ksq, Bitboard& pinners) const { Square s; Bitboard sliders, result = EmptyBoardBB; @@ -362,7 +375,7 @@ Bitboard Position::hidden_checks(Color c, Square ksq) const { // Pinners are sliders, not checkers, that give check when // candidate pinned are removed. - Bitboard pinners = (FindPinned ? sliders & ~checkersBB : sliders); + pinners = (FindPinned ? sliders & ~checkersBB : sliders); if (Piece == ROOK) pinners &= rook_attacks_bb(ksq, occupied_squares() ^ candidate_pinned); @@ -371,12 +384,16 @@ Bitboard Position::hidden_checks(Color c, Square ksq) const { // Finally for each pinner find the corresponding pinned piece (if same color of king) // or discovery checker (if opposite color) among the candidates. - while (pinners) + Bitboard p = pinners; + while (p) { - s = pop_1st_bit(&pinners); + s = pop_1st_bit(&p); result |= (squares_between(s, ksq) & candidate_pinned); } } + else + pinners = EmptyBoardBB; + return result; } @@ -461,22 +478,12 @@ void Position::find_checkers() { } -/// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal. -/// There are two versions of this function: One which takes only a -/// move as input, and one which takes a move and a bitboard of pinned -/// pieces. The latter function is faster, and should always be preferred -/// when a pinned piece bitboard has already been computed. - -bool Position::pl_move_is_legal(Move m) const { - - return pl_move_is_legal(m, pinned_pieces(side_to_move())); -} +/// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal -bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { +bool Position::pl_move_is_legal(Move m) const { assert(is_ok()); assert(move_is_ok(m)); - assert(pinned == pinned_pieces(side_to_move())); // If we're in check, all pseudo-legal moves are legal, because our // check evasion generator only generates true legal moves. @@ -524,34 +531,24 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. - return ( !bit_is_set(pinned, from) + return ( !bit_is_set(pinned_pieces(us), from) || (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq))); } -/// Position::move_is_check() tests whether a pseudo-legal move is a check. -/// There are two versions of this function: One which takes only a move as -/// input, and one which takes a move and a bitboard of discovered check -/// candidates. The latter function is faster, and should always be preferred -/// when a discovered check candidates bitboard has already been computed. +/// Position::move_is_check() tests whether a pseudo-legal move is a check bool Position::move_is_check(Move m) const { - Bitboard dc = discovered_check_candidates(side_to_move()); - return move_is_check(m, dc); -} - -bool Position::move_is_check(Move m, Bitboard dcCandidates) const { - assert(is_ok()); assert(move_is_ok(m)); - assert(dcCandidates == discovered_check_candidates(side_to_move())); Color us = side_to_move(); Color them = opposite_color(us); Square from = move_from(m); Square to = move_to(m); Square ksq = king_square(them); + Bitboard dcCandidates = discovered_check_candidates(us); assert(color_of_piece_on(from) == us); assert(piece_on(ksq) == piece_of_color_and_type(them, KING)); @@ -672,48 +669,6 @@ bool Position::move_is_capture(Move m) const { } -/// Position::backup() is called when making a move. All information -/// necessary to restore the position when the move is later unmade -/// is saved to an UndoInfo object. The function Position::restore -/// does the reverse operation: When one does a backup followed by -/// a restore with the same UndoInfo object, the position is restored -/// to the state before backup was called. - -void Position::backup(UndoInfo& u) const { - - u.castleRights = castleRights; - u.epSquare = epSquare; - u.checkersBB = checkersBB; - u.key = key; - u.pawnKey = pawnKey; - u.materialKey = materialKey; - u.rule50 = rule50; - u.lastMove = lastMove; - u.mgValue = mgValue; - u.egValue = egValue; - u.capture = NO_PIECE_TYPE; -} - - -/// Position::restore() is called when unmaking a move. It copies back -/// the information backed up during a previous call to Position::backup. - -void Position::restore(const UndoInfo& u) { - - castleRights = u.castleRights; - epSquare = u.epSquare; - checkersBB = u.checkersBB; - key = u.key; - pawnKey = u.pawnKey; - materialKey = u.materialKey; - rule50 = u.rule50; - lastMove = u.lastMove; - mgValue = u.mgValue; - egValue = u.egValue; - // u.capture is restored in undo_move() -} - - /// Position::update_checkers() is a private method to udpate chekers info template @@ -737,25 +692,20 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square /// Position::do_move() makes a move, and backs up all information necessary /// to undo the move to an UndoInfo object. The move is assumed to be legal. /// Pseudo-legal moves should be filtered out before this function is called. -/// There are two versions of this function, one which takes only the move and -/// the UndoInfo as input, and one which takes a third parameter, a bitboard of -/// discovered check candidates. The second version is faster, because knowing -/// the discovered check candidates makes it easier to update the checkersBB -/// member variable in the position object. void Position::do_move(Move m, UndoInfo& u) { - do_move(m, u, discovered_check_candidates(side_to_move())); -} - -void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { - assert(is_ok()); assert(move_is_ok(m)); + // Get now the current (pre-move) dc candidates that we will use + // in update_checkers(). + Bitboard oldDcCandidates = discovered_check_candidates(side_to_move()); + // Back up the necessary information to our UndoInfo object (except the // captured piece, which is taken care of later. - backup(u); + u = undoInfoUnion; + u.capture = NO_PIECE_TYPE; // Save the current key to the history[] array, in order to be able to // detect repetition draws. @@ -765,6 +715,10 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { // case of non-reversible moves is taken care of later. rule50++; + // Reset pinned bitboard and its friends + for (Color c = WHITE; c <= BLACK; c++) + pinners[c] = pinned[c] = dcCandidates[c] = ~EmptyBoardBB; + if (move_is_castle(m)) do_castle_move(m); else if (move_promotion(m)) @@ -856,12 +810,12 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { Square ksq = king_square(them); switch (piece) { - case PAWN: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; - case KNIGHT: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; - case BISHOP: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; - case ROOK: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; - case QUEEN: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; - case KING: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case PAWN: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; + case KNIGHT: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; + case BISHOP: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; + case ROOK: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; + case QUEEN: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; + case KING: update_checkers(&checkersBB, ksq, from, to, oldDcCandidates); break; default: assert(false); break; } } @@ -1212,7 +1166,7 @@ void Position::undo_move(Move m, const UndoInfo &u) { // Restore information from our UndoInfo object (except the captured piece, // which is taken care of later) - restore(u); + undoInfoUnion = u; if (move_is_castle(m)) undo_castle_move(m); @@ -1719,6 +1673,8 @@ void Position::clear() { } checkersBB = EmptyBoardBB; + for (Color c = WHITE; c <= BLACK; c++) + pinners[c] = pinned[c] = dcCandidates[c] = ~EmptyBoardBB; lastMove = MOVE_NONE; @@ -1861,7 +1817,7 @@ Key Position::compute_material_key() const { /// up, and to verify that the scores are correctly updated by do_move /// and undo_move when the program is running in debug mode. -Value Position::compute_mg_value() const { +Value Position::compute_value(GamePhase p) const { Value result = Value(0); Bitboard b; @@ -1875,31 +1831,12 @@ Value Position::compute_mg_value() const { { s = pop_1st_bit(&b); assert(piece_on(s) == piece_of_color_and_type(c, pt)); - result += mg_pst(c, pt, s); + result += (p == MidGame ? mg_pst(c, pt, s) : eg_pst(c, pt, s)); } } - result += (side_to_move() == WHITE)? TempoValueMidgame / 2 : -TempoValueMidgame / 2; - return result; -} -Value Position::compute_eg_value() const { - - Value result = Value(0); - Bitboard b; - Square s; - - for (Color c = WHITE; c <= BLACK; c++) - for (PieceType pt = PAWN; pt <= KING; pt++) - { - b = pieces_of_color_and_type(c, pt); - while(b) - { - s = pop_1st_bit(&b); - assert(piece_on(s) == piece_of_color_and_type(c, pt)); - result += eg_pst(c, pt, s); - } - } - result += (side_to_move() == WHITE)? TempoValueEndgame / 2 : -TempoValueEndgame / 2; + const Value TempoValue = (p == MidGame ? TempoValueMidgame : TempoValueEndgame); + result += (side_to_move() == WHITE)? TempoValue / 2 : -TempoValue / 2; return result; } @@ -2120,8 +2057,8 @@ void Position::flipped_copy(const Position &pos) { materialKey = compute_material_key(); // Incremental scores - mgValue = compute_mg_value(); - egValue = compute_eg_value(); + mgValue = compute_value(MidGame); + egValue = compute_value(EndGame); // Material npMaterial[WHITE] = compute_non_pawn_material(WHITE); @@ -2250,10 +2187,10 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) (*failedStep)++; if (debugIncrementalEval) { - if (mgValue != compute_mg_value()) + if (mgValue != compute_value(MidGame)) return false; - if (egValue != compute_eg_value()) + if (egValue != compute_value(EndGame)) return false; }