- // check_is_dangerous() tests if a checking move can be pruned in qsearch()
-
- bool check_is_dangerous(Position& pos, Move move, Value futilityBase, Value beta)
- {
- Piece pc = pos.piece_moved(move);
- Square from = from_sq(move);
- Square to = to_sq(move);
- Color them = ~pos.side_to_move();
- Square ksq = pos.king_square(them);
- Bitboard enemies = pos.pieces(them);
- Bitboard kingAtt = pos.attacks_from<KING>(ksq);
- Bitboard occ = pos.pieces() ^ from ^ ksq;
- Bitboard oldAtt = pos.attacks_from(pc, from, occ);
- Bitboard newAtt = pos.attacks_from(pc, to, occ);
-
- // Checks which give opponent's king at most one escape square are dangerous
- if (!more_than_one(kingAtt & ~(enemies | newAtt | to)))
- return true;
-
- // Queen contact check is very dangerous
- if (type_of(pc) == QUEEN && (kingAtt & to))
- return true;
-
- // Creating new double threats with checks is dangerous
- Bitboard b = (enemies ^ ksq) & newAtt & ~oldAtt;
- while (b)
- {
- // Note that here we generate illegal "double move"!
- if (futilityBase + PieceValue[EG][pos.piece_on(pop_lsb(&b))] >= beta)
- return true;
- }
-
- return false;
- }
-
-
- // yields_to_threat() tests whether the move at previous ply yields to the so
- // called threat move (the best move returned from a null search that fails
- // low). Here 'yields to' means that the move somehow made the threat possible
- // for instance if the moving piece is the same in both moves.
-
- bool yields_to_threat(const Position& pos, Move move, Move threat) {
-
- assert(is_ok(move));
- assert(is_ok(threat));
- assert(color_of(pos.piece_on(from_sq(threat))) == ~pos.side_to_move());
-
- Square mfrom = from_sq(move);
- Square mto = to_sq(move);
- Square tfrom = from_sq(threat);
- Square tto = to_sq(threat);
-
- // The piece is the same or threat's destination was vacated by the move
- if (mto == tfrom || tto == mfrom)
- return true;
-
- // Threat moves through the vacated square
- if (between_bb(tfrom, tto) & mfrom)
- return true;
-
- // Threat's destination is defended by the move's piece
- Bitboard matt = pos.attacks_from(pos.piece_on(mto), mto, pos.pieces() ^ tfrom);
- if (matt & tto)
- return true;
-
- // Threat gives a discovered check through the move's checking piece
- if (matt & pos.king_square(pos.side_to_move()))
- {
- assert(between_bb(mto, pos.king_square(pos.side_to_move())) & tfrom);
- return true;
- }
-
- return false;
- }
-
-
- // prevents_threat() tests whether a move is able to defend against the so
- // called threat move (the best move returned from a null search that fails
- // low). In this case will not be pruned.
-
- bool prevents_threat(const Position& pos, Move move, Move threat) {
-
- assert(is_ok(move));
- assert(is_ok(threat));
- assert(!pos.is_capture_or_promotion(move));
- assert(!pos.is_passed_pawn_push(move));
-
- Square mfrom = from_sq(move);
- Square mto = to_sq(move);
- Square tfrom = from_sq(threat);
- Square tto = to_sq(threat);
-
- // Don't prune moves of the threatened piece
- if (mfrom == tto)
- return true;
-
- // If the threatened piece has value less than or equal to the value of the
- // threat piece, don't prune moves which defend it.
- if ( pos.is_capture(threat)
- && ( PieceValue[MG][pos.piece_on(tfrom)] >= PieceValue[MG][pos.piece_on(tto)]
- || type_of(pos.piece_on(tfrom)) == KING))
- {
- // Update occupancy as if the piece and the threat are moving
- Bitboard occ = pos.pieces() ^ mfrom ^ mto ^ tfrom;
- Piece piece = pos.piece_on(mfrom);
-
- // The moved piece attacks the square 'tto' ?
- if (pos.attacks_from(piece, mto, occ) & tto)
- return true;
-
- // Scan for possible X-ray attackers behind the moved piece
- Bitboard xray = (attacks_bb< ROOK>(tto, occ) & pos.pieces(color_of(piece), QUEEN, ROOK))
- | (attacks_bb<BISHOP>(tto, occ) & pos.pieces(color_of(piece), QUEEN, BISHOP));
-
- // Verify attackers are triggered by our move and not already existing
- if (xray && (xray ^ (xray & pos.attacks_from<QUEEN>(tto))))
- return true;
- }
-
- // Don't prune safe moves which block the threat path
- if ((between_bb(tfrom, tto) & mto) && pos.see_sign(move) >= 0)
- return true;
-
- return false;
- }
-
-
- // When playing with strength handicap choose best move among the MultiPV set
- // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.