From f9f30412e798b4ba06375a383a85a9e65bfe299f Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 28 Feb 2009 09:18:29 +0100 Subject: [PATCH 1/1] Compute pinned and friends incrementally In do_move() use previous pinned bitboards values to compute the new one after the move. In particulary we end up with the same bitboards in most cases. So detect these cases and just keep the old values. This should speedup a lot this slow computation in a very hot path so that we can use this important info everywhere in the code at very cheap cost. Signed-off-by: Marco Costalba --- src/position.cpp | 100 +++++++++++++++++++++++++++++++++-------------- src/position.h | 5 ++- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 7725b934..05e093a8 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -207,7 +207,7 @@ void Position::from_fen(const std::string& fen) { castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; find_checkers(); - find_pinned(); + find_hidden_checks(); st->key = compute_key(); st->pawnKey = compute_pawn_key(); @@ -446,23 +446,25 @@ void Position::find_checkers() { st->checkersBB = attacks_to(king_square(us), opposite_color(us)); } +/// Position:find_hidden_checks() computes the pinned, pinners and dcCandidates +/// bitboards. There are two versions of this function. One takes a color and +/// computes bitboards relative to that color only, the other computes both +/// colors. Bitboard checkersBB must be already updated. -/// Position:find_pinned() computes the pinned, pinners and dcCandidates -/// bitboards for both colors. Bitboard checkersBB must be already updated. - -void Position::find_pinned() { +void Position::find_hidden_checks(Color us) { Bitboard p1, p2; - Square ksq; + Color them = opposite_color(us); + Square ksq = king_square(them); + st->pinned[them] = hidden_checks(them, ksq, p1) | hidden_checks(them, ksq, p2); + st->pinners[them] = p1 | p2; + st->dcCandidates[us] = hidden_checks(us, ksq, p1) | hidden_checks(us, ksq, p2); +} + +void Position::find_hidden_checks() { for (Color c = WHITE; c <= BLACK; c++) - { - ksq = king_square(c); - st->pinned[c] = hidden_checks(c, ksq, p1) | hidden_checks(c, ksq, p2); - st->pinners[c] = p1 | p2; - ksq = king_square(opposite_color(c)); - st->dcCandidates[c] = hidden_checks(c, ksq, p1) | hidden_checks(c, ksq, p2); - } + find_hidden_checks(c); } @@ -657,7 +659,8 @@ bool Position::move_is_capture(Move m) const { } -/// Position::update_checkers() is a private method to udpate chekers info +/// Position::update_checkers() udpates chekers info given the move. It is called +/// in do_move() and is faster then find_checkers(). template inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, @@ -677,22 +680,47 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square } -/// Position::init_new_state() copies from the current state the fields -/// that will be updated incrementally, skips the fields, like bitboards -/// that will be recalculated form scratch anyway. +/// Position::update_hidden_checks() udpates pinned, pinners and dcCandidates +/// bitboards incrementally, given the move. It is called in do_move and is +/// faster then find_hidden_checks(). + +void Position::update_hidden_checks(Square from, Square to) { + + Color us = sideToMove; + Color them = opposite_color(us); + Square ksq = king_square(opposite_color(us)); + + Bitboard moveSquares = EmptyBoardBB; + set_bit(&moveSquares, from); + set_bit(&moveSquares, to); + + // Our moving piece could have been a possible pinner or hidden checker behind a dcCandidates? + bool checkerMoved = (st->dcCandidates[us] | st->pinners[them]) && (moveSquares & sliders()); + + // If we are moving from/to an opponent king attack direction and we was a possible hidden checker + // or there exsist some possible hidden checker on that line then recalculate the position + // otherwise skip because our dcCandidates and opponent pinned pieces are not changed. + if ( (moveSquares & RookPseudoAttacks[ksq]) && (checkerMoved || (rooks_and_queens(us) & RookPseudoAttacks[ksq])) + || (moveSquares & BishopPseudoAttacks[ksq]) && (checkerMoved || (bishops_and_queens(us) & BishopPseudoAttacks[ksq]))) + find_hidden_checks(us); + + ksq = king_square(us); -void Position::init_new_state(StateInfo& newSt) { + if (ksq == to) + { + find_hidden_checks(them); + return; + } - newSt.key = st->key; - newSt.pawnKey = st->pawnKey; - newSt.materialKey = st->materialKey; - newSt.castleRights = st->castleRights; - newSt.rule50 = st->rule50; - newSt.epSquare = st->epSquare; - newSt.mgValue = st->mgValue; - newSt.egValue = st->egValue; - newSt.capture = NO_PIECE_TYPE; - newSt.previous = st; + // It is possible that we have captured an opponent hidden checker? + Bitboard checkerCaptured = (st->dcCandidates[them] | st->pinners[us]) && st->capture; + + // If we are moving from/to an our king attack direction and there was/is some possible + // opponent hidden checker then calculate the position otherwise skip because opponent + // dcCandidates and our pinned pieces are not changed. + if ( (moveSquares & RookPseudoAttacks[ksq]) && (checkerCaptured || (rooks_and_queens(them) & RookPseudoAttacks[ksq])) + || (moveSquares & BishopPseudoAttacks[ksq]) && (checkerCaptured || (bishops_and_queens(them) & BishopPseudoAttacks[ksq]))) + find_hidden_checks(them); } @@ -712,7 +740,9 @@ void Position::do_move(Move m, StateInfo& newSt) { // Copy some fields of old state to our new StateInfo object (except the // captured piece, which is taken care of later) and switch state pointer // to point to the new, ready to be updated, state. - init_new_state(newSt); + newSt = *st; + newSt.capture = NO_PIECE_TYPE; + newSt.previous = st; st = &newSt; // Save the current key to the history[] array, in order to be able to @@ -820,10 +850,11 @@ void Position::do_move(Move m, StateInfo& newSt) { case KING: update_checkers(&st->checkersBB, ksq, from, to, oldDcCandidates); break; default: assert(false); break; } + + update_hidden_checks(from, to); } // Finish - find_pinned(); st->key ^= zobSideToMove; sideToMove = opposite_color(sideToMove); gamePly++; @@ -972,6 +1003,9 @@ void Position::do_castle_move(Move m) { // Update checkers BB st->checkersBB = attacks_to(king_square(them), us); + + // Update hidden checks + find_hidden_checks(); } @@ -1062,6 +1096,9 @@ void Position::do_promotion_move(Move m) { // Update checkers BB st->checkersBB = attacks_to(king_square(them), us); + + // Update hidden checks + find_hidden_checks(); } @@ -1144,6 +1181,9 @@ void Position::do_ep_move(Move m) { // Update checkers BB st->checkersBB = attacks_to(king_square(them), us); + + // Update hidden checks + find_hidden_checks(); } diff --git a/src/position.h b/src/position.h index 676f68ef..11d31f8a 100644 --- a/src/position.h +++ b/src/position.h @@ -295,7 +295,6 @@ private: void allow_ooo(Color c); // Helper functions for doing and undoing moves - void init_new_state(StateInfo& newSt); void do_capture_move(Move m, PieceType capture, Color them, Square to); void do_castle_move(Move m); void do_promotion_move(Move m); @@ -304,7 +303,9 @@ private: void undo_promotion_move(Move m); void undo_ep_move(Move m); void find_checkers(); - void find_pinned(); + void find_hidden_checks(Color us); + void find_hidden_checks(); + void update_hidden_checks(Square from, Square to); template void update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, Square to, Bitboard dcCandidates); -- 2.39.2