1
0
Fork 0

Revert hidden checkers rework

It is slower the previous uglier but faster code.

So completely restore old one for now :-(

Just leave in the rework of status backup/restore in do_move().

We will cherry pick bits of previous work once we are sure
we have fixed the performance regression.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
sf_2.3.1_base
Marco Costalba 2009-03-02 16:20:00 +01:00
parent 9b6b9e67fe
commit c02613860a
7 changed files with 111 additions and 201 deletions

View File

@ -166,14 +166,13 @@ int generate_noncaptures(const Position& pos, MoveStack* mlist) {
/// generate_checks() generates all pseudo-legal non-capturing, non-promoting
/// checks. It returns the number of generated moves.
int generate_checks(const Position& pos, MoveStack* mlist) {
int generate_checks(const Position& pos, MoveStack* mlist, Bitboard dc) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
Square ksq = pos.king_square(opposite_color(us));
Bitboard dc = pos.discovered_check_candidates(us);
MoveStack* mlist_start = mlist;
assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING));
@ -205,7 +204,7 @@ int generate_checks(const Position& pos, MoveStack* mlist) {
/// in check. Unlike the other move generation functions, this one generates
/// only legal moves. It returns the number of generated moves.
int generate_evasions(const Position& pos, MoveStack* mlist) {
int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) {
assert(pos.is_ok());
assert(pos.is_check());
@ -259,7 +258,6 @@ int generate_evasions(const Position& pos, MoveStack* mlist) {
if (!(checkers & (checkers - 1))) // Only one bit set?
{
Square checksq = first_1(checkers);
Bitboard pinned = pos.pinned_pieces(us);
assert(pos.color_of_piece_on(checksq) == them);
@ -349,8 +347,10 @@ int generate_legal_moves(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
if (pos.is_check())
return generate_evasions(pos, mlist);
return generate_evasions(pos, mlist, pinned);
// Generate pseudo-legal moves
int n = generate_captures(pos, mlist);
@ -358,7 +358,7 @@ int generate_legal_moves(const Position& pos, MoveStack* mlist) {
// Remove illegal moves from the list
for (int i = 0; i < n; i++)
if (!pos.pl_move_is_legal(mlist[i].move))
if (!pos.pl_move_is_legal(mlist[i].move, pinned))
mlist[i--].move = mlist[--n].move;
return n;
@ -371,11 +371,12 @@ int generate_legal_moves(const Position& pos, MoveStack* mlist) {
/// returned. If not, the function returns false. This function must
/// only be used when the side to move is not in check.
bool move_is_legal(const Position& pos, const Move m) {
bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
assert(pos.is_ok());
assert(!pos.is_check());
assert(move_is_ok(m));
assert(pinned == pos.pinned_pieces(pos.side_to_move()));
Color us = pos.side_to_move();
Color them = opposite_color(us);
@ -402,7 +403,7 @@ bool move_is_legal(const Position& pos, const Move m) {
assert(pos.piece_on(to - pawn_push(us)) == piece_of_color_and_type(them, PAWN));
// The move is pseudo-legal, check if it is also legal
return pos.pl_move_is_legal(m);
return pos.pl_move_is_legal(m, pinned);
}
// Castling moves
@ -534,12 +535,12 @@ bool move_is_legal(const Position& pos, const Move m) {
return false;
}
// The move is pseudo-legal, check if it is also legal
return pos.pl_move_is_legal(m);
return pos.pl_move_is_legal(m, pinned);
}
// Luckly we can handle all the other pieces in one go
return ( pos.piece_attacks_square(pos.piece_on(from), from, to)
&& pos.pl_move_is_legal(m)
&& pos.pl_move_is_legal(m, pinned)
&& !move_promotion(m));
}

View File

@ -34,10 +34,10 @@
extern int generate_captures(const Position &pos, MoveStack *mlist);
extern int generate_noncaptures(const Position &pos, MoveStack *mlist);
extern int generate_checks(const Position &pos, MoveStack *mlist);
extern int generate_evasions(const Position &pos, MoveStack *mlist);
extern int generate_checks(const Position &pos, MoveStack *mlist, Bitboard dc);
extern int generate_evasions(const Position &pos, MoveStack *mlist, Bitboard pinned);
extern int generate_legal_moves(const Position &pos, MoveStack *mlist);
extern bool move_is_legal(const Position &pos, const Move m);
extern bool move_is_legal(const Position &pos, const Move m, Bitboard pinned);
#endif // !defined(MOVEGEN_H_INCLUDED)

View File

@ -96,6 +96,9 @@ MovePicker::MovePicker(const Position& p, bool pv, Move ttm,
else
phaseIndex = (noCaptures ? NoMovesPhaseIndex : QsearchWithoutChecksPhaseIndex);
dc = p.discovered_check_candidates(us);
pinned = p.pinned_pieces(us);
finished = false;
}
@ -127,7 +130,7 @@ Move MovePicker::get_next_move() {
if (ttMove != MOVE_NONE)
{
assert(move_is_ok(ttMove));
if (move_is_legal(pos, ttMove))
if (move_is_legal(pos, ttMove, pinned))
return ttMove;
}
break;
@ -136,7 +139,7 @@ Move MovePicker::get_next_move() {
if (mateKiller != MOVE_NONE)
{
assert(move_is_ok(mateKiller));
if (move_is_legal(pos, mateKiller))
if (move_is_legal(pos, mateKiller, pinned))
return mateKiller;
}
break;
@ -159,7 +162,7 @@ Move MovePicker::get_next_move() {
case PH_EVASIONS:
assert(pos.is_check());
numOfMoves = generate_evasions(pos, moves);
numOfMoves = generate_evasions(pos, moves, pinned);
score_evasions();
movesPicked = 0;
break;
@ -171,7 +174,7 @@ Move MovePicker::get_next_move() {
break;
case PH_QCHECKS:
numOfMoves = generate_checks(pos, moves);
numOfMoves = generate_checks(pos, moves, dc);
movesPicked = 0;
break;
@ -391,7 +394,7 @@ Move MovePicker::pick_move_from_list() {
moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move))
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break;
@ -411,7 +414,7 @@ Move MovePicker::pick_move_from_list() {
moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move))
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break;
@ -439,7 +442,7 @@ Move MovePicker::pick_move_from_list() {
move = badCaptures[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move))
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break;
@ -454,7 +457,7 @@ Move MovePicker::pick_move_from_list() {
moves[bestIndex] = moves[movesPicked++];
// Remember to change the line below if we decide to hash the qsearch!
// Maybe also postpone the legality check until after futility pruning?
if (/* move != ttMove && */ pos.pl_move_is_legal(move))
if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned))
return move;
}
break;
@ -468,7 +471,7 @@ Move MovePicker::pick_move_from_list() {
{
move = moves[movesPicked++].move;
// Remember to change the line below if we decide to hash the qsearch!
if (/* move != ttMove && */ pos.pl_move_is_legal(move))
if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned))
return move;
}
break;

View File

@ -69,6 +69,7 @@ public:
int number_of_moves() const;
int current_move_score() const;
MovegenPhase current_move_type() const;
Bitboard discovered_check_candidates() const;
static void init_phase_table();
@ -83,6 +84,7 @@ private:
const Position& pos;
Move ttMove, mateKiller, killer1, killer2;
Bitboard pinned, dc;
MoveStack moves[256], badCaptures[64];
bool pvNode;
Depth depth;
@ -107,4 +109,12 @@ inline int MovePicker::number_of_moves() const {
return numOfMoves;
}
/// MovePicker::discovered_check_candidates() returns a bitboard containing
/// all pieces which can possibly give discovered check. This bitboard is
/// computed by the constructor function.
inline Bitboard MovePicker::discovered_check_candidates() const {
return dc;
}
#endif // !defined(MOVEPICK_H_INCLUDED)

View File

@ -207,7 +207,6 @@ void Position::from_fen(const std::string& fen) {
castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO;
find_checkers();
find_hidden_checks();
st->key = compute_key();
st->pawnKey = compute_pawn_key();
@ -321,6 +320,29 @@ void Position::copy(const Position &pos) {
}
/// Position:pinned_pieces() returns a bitboard of all pinned (against the
/// king) pieces for the given color.
Bitboard Position::pinned_pieces(Color c) const {
Bitboard p;
Square ksq = king_square(c);
return hidden_checks<ROOK, true>(c, ksq, p) | hidden_checks<BISHOP, true>(c, ksq, p);
}
/// 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.
Bitboard Position::discovered_check_candidates(Color c) const {
Bitboard p;
Square ksq = king_square(opposite_color(c));
return hidden_checks<ROOK, false>(c, ksq, p) | hidden_checks<BISHOP, false>(c, ksq, p);
}
/// 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
@ -446,38 +468,19 @@ 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.
void Position::find_hidden_checks(Color us, unsigned int types) {
Bitboard p1, p2;
Color them = opposite_color(us);
Square ksq = king_square(them);
if (types & Pinned)
{
st->pinned[them] = hidden_checks<ROOK, true>(them, ksq, p1) | hidden_checks<BISHOP, true>(them, ksq, p2);
st->pinners[them] = p1 | p2;
}
if (types & DcCandidates)
st->dcCandidates[us] = hidden_checks<ROOK, false>(us, ksq, p1) | hidden_checks<BISHOP, false>(us, ksq, p2);
}
void Position::find_hidden_checks() {
for (Color c = WHITE; c <= BLACK; c++)
find_hidden_checks(c, Pinned | DcCandidates);
}
/// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal
bool Position::pl_move_is_legal(Move m) const {
return pl_move_is_legal(m, pinned_pieces(side_to_move()));
}
bool Position::pl_move_is_legal(Move m, Bitboard pinned) 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.
@ -525,7 +528,7 @@ bool Position::pl_move_is_legal(Move m) 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_pieces(us), from)
return ( !bit_is_set(pinned, from)
|| (direction_between_squares(from, ksq) == direction_between_squares(move_to(m), ksq)));
}
@ -534,15 +537,21 @@ bool Position::pl_move_is_legal(Move m) const {
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));
@ -684,88 +693,20 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
}
/// 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] || bit_is_set(st->pinners[them], from)) && (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])))
{
// If the move gives direct check and we don't have pinners/dc cadidates
// then we can be sure that we won't have them also after the move if
// we are not moving from a possible king attack direction.
bool outsideChecker = false;
if ( bit_is_set(st->checkersBB, to)
&& !(bit_is_set(RookPseudoAttacks[ksq], from) && (checkerMoved || (rooks_and_queens(us) & RookPseudoAttacks[ksq])))
&& !(bit_is_set(BishopPseudoAttacks[ksq], from) && (checkerMoved || (bishops_and_queens(us) & BishopPseudoAttacks[ksq]))))
outsideChecker = true;
if (!outsideChecker || st->pinned[them])
find_hidden_checks(us, Pinned);
if (!outsideChecker || st->dcCandidates[us] || bit_is_set(st->pinned[them], to))
find_hidden_checks(us, DcCandidates);
}
ksq = king_square(us);
if (ksq == to)
{
find_hidden_checks(them, Pinned | DcCandidates);
return;
}
// It is possible that we have captured an opponent hidden checker?
Bitboard checkerCaptured = st->capture && (st->dcCandidates[them] || bit_is_set(st->pinners[us], to));
// 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, Pinned);
// If we don't have opponent dc candidates and we are moving in the
// attack line then won't be any dc candidates also after the move.
if ( st->dcCandidates[them]
|| (bit_is_set(RookPseudoAttacks[ksq], from) && (rooks_and_queens(them) & RookPseudoAttacks[ksq]))
|| (bit_is_set(BishopPseudoAttacks[ksq], from) && (bishops_and_queens(them) & BishopPseudoAttacks[ksq])))
find_hidden_checks(them, DcCandidates);
}
}
/// Position::do_move() makes a move, and saves all information necessary
/// to a StateInfo object. The move is assumed to be legal.
/// Pseudo-legal moves should be filtered out before this function is called.
void Position::do_move(Move m, StateInfo& newSt) {
do_move(m, newSt, discovered_check_candidates(side_to_move()));
}
void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
assert(is_ok());
assert(move_is_ok(m));
// Get now the current (before to move) dc candidates that we will use
// in update_checkers().
Bitboard oldDcCandidates = discovered_check_candidates(side_to_move());
// 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.
@ -871,16 +812,14 @@ void Position::do_move(Move m, StateInfo& newSt) {
Square ksq = king_square(them);
switch (piece)
{
case PAWN: update_checkers<PAWN>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case KNIGHT: update_checkers<KNIGHT>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case BISHOP: update_checkers<BISHOP>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case ROOK: update_checkers<ROOK>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case QUEEN: update_checkers<QUEEN>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case KING: update_checkers<KING>(&st->checkersBB, ksq, from, to, oldDcCandidates); break;
case PAWN: update_checkers<PAWN>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case KNIGHT: update_checkers<KNIGHT>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case BISHOP: update_checkers<BISHOP>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case ROOK: update_checkers<ROOK>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case QUEEN: update_checkers<QUEEN>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case KING: update_checkers<KING>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
default: assert(false); break;
}
update_hidden_checks(from, to);
}
// Finish
@ -1032,9 +971,6 @@ void Position::do_castle_move(Move m) {
// Update checkers BB
st->checkersBB = attacks_to(king_square(them), us);
// Update hidden checks
find_hidden_checks();
}
@ -1125,9 +1061,6 @@ void Position::do_promotion_move(Move m) {
// Update checkers BB
st->checkersBB = attacks_to(king_square(them), us);
// Update hidden checks
find_hidden_checks();
}
@ -1210,9 +1143,6 @@ void Position::do_ep_move(Move m) {
// Update checkers BB
st->checkersBB = attacks_to(king_square(them), us);
// Update hidden checks
find_hidden_checks();
}
@ -1597,11 +1527,6 @@ int Position::see(Square from, Square to) const {
Color us = (from != SQ_NONE ? color_of_piece_on(from) : opposite_color(color_of_piece_on(to)));
Color them = opposite_color(us);
// Initialize pinned and pinners bitboards
Bitboard pinned[2], pinners[2];
pinned[us] = pinned_pieces(us, pinners[us]);
pinned[them] = pinned_pieces(them, pinners[them]);
// Initialize pieces
Piece piece = piece_on(from);
Piece capture = piece_on(to);
@ -1634,17 +1559,6 @@ int Position::see(Square from, Square to) const {
| (pawn_attacks(WHITE, to) & pawns(BLACK))
| (pawn_attacks(BLACK, to) & pawns(WHITE));
// Remove our pinned pieces from attacks if the captured piece is not
// a pinner, otherwise we could remove a valid "capture the pinner" attack.
if (pinned[us] != EmptyBoardBB && !bit_is_set(pinners[us], to))
attackers &= ~pinned[us];
// Remove opponent pinned pieces from attacks if the moving piece is not
// a pinner, otherwise we could remove a piece that is no more pinned
// due to our pinner piece is moving away.
if (pinned[them] != EmptyBoardBB && !bit_is_set(pinners[them], from))
attackers &= ~pinned[them];
if (from != SQ_NONE)
break;
@ -1707,12 +1621,6 @@ int Position::see(Square from, Square to) const {
lastCapturingPieceValue = seeValues[pt];
c = opposite_color(c);
// Remove pinned pieces from attackers
if ( pinned[c] != EmptyBoardBB
&& !bit_is_set(pinners[c], to)
&& !(pinners[c] & attackers))
attackers &= ~pinned[c];
// Stop after a king capture
if (pt == KING && (attackers & pieces_of_color(c)))
{

View File

@ -79,7 +79,7 @@ enum CastleRights {
/// must be passed as a parameter.
struct StateInfo {
Bitboard pinners[2], pinned[2], dcCandidates[2], checkersBB;
Bitboard checkersBB;
Key key, pawnKey, materialKey;
int castleRights, rule50;
Square epSquare;
@ -219,7 +219,9 @@ public:
// Properties of moves
bool pl_move_is_legal(Move m) const;
bool pl_move_is_legal(Move m, Bitboard pinned) const;
bool move_is_check(Move m) const;
bool move_is_check(Move m, Bitboard dcCandidates) const;
bool move_is_capture(Move m) const;
bool move_is_deep_pawn_push(Move m) const;
bool move_is_pawn_push_to_7th(Move m) const;
@ -242,6 +244,7 @@ public:
// Doing and undoing moves
void setStartState(const StateInfo& st);
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, Bitboard dcCandidates);
void undo_move(Move m);
void do_null_move(StateInfo& st);
void undo_null_move();
@ -289,11 +292,6 @@ public:
private:
enum {
Pinned = 1,
DcCandidates = 2
};
// Initialization helper functions (used while setting up a position)
void clear();
void put_piece(Piece p, Square s);
@ -309,9 +307,6 @@ private:
void undo_promotion_move(Move m);
void undo_ep_move(Move m);
void find_checkers();
void find_hidden_checks(Color us, unsigned int types);
void find_hidden_checks();
void update_hidden_checks(Square from, Square to);
template<PieceType Piece>
void update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, Square to, Bitboard dcCandidates);
@ -566,19 +561,6 @@ inline Bitboard Position::piece_attacks<KING>(Square s) const {
return StepAttackBB[KING][s];
}
inline Bitboard Position::pinned_pieces(Color c) const {
return st->pinned[c];
}
inline Bitboard Position::pinned_pieces(Color c, Bitboard& p) const {
p = st->pinners[c];
return st->pinned[c];
}
inline Bitboard Position::discovered_check_candidates(Color c) const {
return st->dcCandidates[c];
}
inline Bitboard Position::checkers() const {
return st->checkersBB;
}

View File

@ -290,8 +290,8 @@ namespace {
bool thread_is_available(int slave, int master);
bool idle_thread_exists(int master);
bool split(const Position &pos, SearchStack *ss, int ply,
Value *alpha, Value *beta, Value *bestValue, Depth depth,
int *moves, MovePicker *mp, int master, bool pvNode);
Value *alpha, Value *beta, Value *bestValue, Depth depth, int *moves,
MovePicker *mp, Bitboard dcCandidates, int master, bool pvNode);
void wake_sleeping_threads();
#if !defined(_MSC_VER)
@ -775,6 +775,7 @@ namespace {
Value alpha = -VALUE_INFINITE;
Value beta = VALUE_INFINITE, value;
Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move());
// Loop through all the moves in the root move list
for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
@ -807,7 +808,7 @@ namespace {
newDepth = (Iteration - 2) * OnePly + ext + InitialDepth;
// Make the move, and search it
pos.do_move(move, st);
pos.do_move(move, st, dcCandidates);
if (i < MultiPV)
{
@ -981,6 +982,7 @@ namespace {
Move move, movesSearched[256];
int moveCount = 0;
Value value, bestValue = -VALUE_INFINITE;
Bitboard dcCandidates = mp.discovered_check_candidates();
Color us = pos.side_to_move();
bool isCheck = pos.is_check();
bool mateThreat = pos.has_mate_threat(opposite_color(us));
@ -994,7 +996,7 @@ namespace {
assert(move_is_ok(move));
bool singleReply = (isCheck && mp.number_of_moves() == 1);
bool moveIsCheck = pos.move_is_check(move);
bool moveIsCheck = pos.move_is_check(move, dcCandidates);
bool moveIsCapture = pos.move_is_capture(move);
movesSearched[moveCount++] = ss[ply].currentMove = move;
@ -1012,7 +1014,7 @@ namespace {
// Make and search the move
StateInfo st;
pos.do_move(move, st);
pos.do_move(move, st, dcCandidates);
if (moveCount == 1) // The first move in list is the PV
value = -search_pv(pos, ss, -beta, -alpha, newDepth, ply+1, threadID);
@ -1087,7 +1089,7 @@ namespace {
&& !AbortSearch
&& !thread_should_stop(threadID)
&& split(pos, ss, ply, &alpha, &beta, &bestValue, depth,
&moveCount, &mp, threadID, true))
&moveCount, &mp, dcCandidates, threadID, true))
break;
}
@ -1281,6 +1283,7 @@ namespace {
Move move, movesSearched[256];
int moveCount = 0;
Value value, bestValue = -VALUE_INFINITE;
Bitboard dcCandidates = mp.discovered_check_candidates();
Value futilityValue = VALUE_NONE;
bool useFutilityPruning = UseFutilityPruning
&& depth < SelectiveDepth
@ -1295,7 +1298,7 @@ namespace {
assert(move_is_ok(move));
bool singleReply = (isCheck && mp.number_of_moves() == 1);
bool moveIsCheck = pos.move_is_check(move);
bool moveIsCheck = pos.move_is_check(move, dcCandidates);
bool moveIsCapture = pos.move_is_capture(move);
movesSearched[moveCount++] = ss[ply].currentMove = move;
@ -1335,7 +1338,7 @@ namespace {
// Make and search the move
StateInfo st;
pos.do_move(move, st);
pos.do_move(move, st, dcCandidates);
// Try to reduce non-pv search depth by one ply if move seems not problematic,
// if the move fails high will be re-searched at full depth.
@ -1382,7 +1385,7 @@ namespace {
&& !AbortSearch
&& !thread_should_stop(threadID)
&& split(pos, ss, ply, &beta, &beta, &bestValue, depth, &moveCount,
&mp, threadID, false))
&mp, dcCandidates, threadID, false))
break;
}
@ -1467,6 +1470,7 @@ namespace {
MovePicker mp = MovePicker(pos, pvNode, MOVE_NONE, EmptySearchStack, depth, isCheck ? NULL : &ei);
Move move;
int moveCount = 0;
Bitboard dcCandidates = mp.discovered_check_candidates();
Color us = pos.side_to_move();
bool enoughMaterial = pos.non_pawn_material(us) > RookValueMidgame;
@ -1486,7 +1490,7 @@ namespace {
&& !isCheck
&& !pvNode
&& !move_promotion(move)
&& !pos.move_is_check(move)
&& !pos.move_is_check(move, dcCandidates)
&& !pos.move_is_passed_pawn_push(move))
{
Value futilityValue = staticValue
@ -1514,7 +1518,7 @@ namespace {
// Make and search the move.
StateInfo st;
pos.do_move(move, st);
pos.do_move(move, st, dcCandidates);
Value value = -qsearch(pos, ss, -beta, -alpha, depth-OnePly, ply+1, threadID);
pos.undo_move(move);
@ -1581,7 +1585,7 @@ namespace {
{
assert(move_is_ok(move));
bool moveIsCheck = pos.move_is_check(move);
bool moveIsCheck = pos.move_is_check(move, sp->dcCandidates);
bool moveIsCapture = pos.move_is_capture(move);
lock_grab(&(sp->lock));
@ -1606,7 +1610,7 @@ namespace {
// Make and search the move.
StateInfo st;
pos.do_move(move, st);
pos.do_move(move, st, sp->dcCandidates);
// Try to reduce non-pv search depth by one ply if move seems not problematic,
// if the move fails high will be re-searched at full depth.
@ -1691,7 +1695,7 @@ namespace {
&& !thread_should_stop(threadID)
&& (move = sp->mp->get_next_move(sp->lock)) != MOVE_NONE)
{
bool moveIsCheck = pos.move_is_check(move);
bool moveIsCheck = pos.move_is_check(move, sp->dcCandidates);
bool moveIsCapture = pos.move_is_capture(move);
assert(move_is_ok(move));
@ -1715,7 +1719,7 @@ namespace {
// Make and search the move.
StateInfo st;
pos.do_move(move, st);
pos.do_move(move, st, sp->dcCandidates);
// Try to reduce non-pv search depth by one ply if move seems not problematic,
// if the move fails high will be re-searched at full depth.
@ -2671,8 +2675,9 @@ namespace {
// splitPoint->cpus becomes 0), split() returns true.
bool split(const Position &p, SearchStack *sstck, int ply,
Value *alpha, Value *beta, Value *bestValue,
Depth depth, int *moves, MovePicker *mp, int master, bool pvNode) {
Value *alpha, Value *beta, Value *bestValue, Depth depth, int *moves,
MovePicker *mp, Bitboard dcCandidates, int master, bool pvNode) {
assert(p.is_ok());
assert(sstck != NULL);
assert(ply >= 0 && ply < PLY_MAX);
@ -2708,6 +2713,7 @@ namespace {
splitPoint->alpha = pvNode? *alpha : (*beta - 1);
splitPoint->beta = *beta;
splitPoint->pvNode = pvNode;
splitPoint->dcCandidates = dcCandidates;
splitPoint->bestValue = *bestValue;
splitPoint->master = master;
splitPoint->mp = mp;