- // check_is_dangerous() tests if a checking move can be pruned in qsearch()
-
- bool check_is_dangerous(const 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;
- }
-
-
- // allows() tests whether the 'first' move at previous ply somehow makes the
- // 'second' move possible, for instance if the moving piece is the same in
- // both moves. Normally the second move is the threat (the best move returned
- // from a null search that fails low).
-
- bool allows(const Position& pos, Move first, Move second) {
-
- assert(is_ok(first));
- assert(is_ok(second));
- assert(color_of(pos.piece_on(from_sq(second))) == ~pos.side_to_move());
- assert(color_of(pos.piece_on(to_sq(first))) == ~pos.side_to_move());
-
- Square m1from = from_sq(first);
- Square m2from = from_sq(second);
- Square m1to = to_sq(first);
- Square m2to = to_sq(second);
-
- // The piece is the same or second's destination was vacated by the first move
- if (m1to == m2from || m2to == m1from)
- return true;
-
- // Second one moves through the square vacated by first one
- if (between_bb(m2from, m2to) & m1from)
- return true;
-
- // Second's destination is defended by the first move's piece
- Bitboard m1att = pos.attacks_from(pos.piece_on(m1to), m1to, pos.pieces() ^ m2from);
- if (m1att & m2to)
- return true;
-
- // Second move gives a discovered check through the first's checking piece
- if (m1att & pos.king_square(pos.side_to_move()))
- {
- assert(between_bb(m1to, pos.king_square(pos.side_to_move())) & m2from);
- return true;
- }
-
- return false;
- }
-
-
- // refutes() tests whether a 'first' move is able to defend against a 'second'
- // opponent's move. In this case will not be pruned. Normally the second move
- // is the threat (the best move returned from a null search that fails low).
-
- bool refutes(const Position& pos, Move first, Move second) {
-
- assert(is_ok(first));
- assert(is_ok(second));
-
- Square m1from = from_sq(first);
- Square m2from = from_sq(second);
- Square m1to = to_sq(first);
- Square m2to = to_sq(second);
-
- // Don't prune moves of the threatened piece
- if (m1from == m2to)
- 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(second)
- && ( PieceValue[MG][pos.piece_on(m2from)] >= PieceValue[MG][pos.piece_on(m2to)]
- || type_of(pos.piece_on(m2from)) == KING))
- {
- // Update occupancy as if the piece and the threat are moving
- Bitboard occ = pos.pieces() ^ m1from ^ m1to ^ m2from;
- Piece pc = pos.piece_on(m1from);
-
- // The moved piece attacks the square 'tto' ?
- if (pos.attacks_from(pc, m1to, occ) & m2to)
- return true;
-
- // Scan for possible X-ray attackers behind the moved piece
- Bitboard xray = (attacks_bb< ROOK>(m2to, occ) & pos.pieces(color_of(pc), QUEEN, ROOK))
- | (attacks_bb<BISHOP>(m2to, occ) & pos.pieces(color_of(pc), QUEEN, BISHOP));
-
- // Verify attackers are triggered by our move and not already existing
- if (xray && (xray ^ (xray & pos.attacks_from<QUEEN>(m2to))))
- return true;
- }
-
- // Don't prune safe moves which block the threat path
- if ((between_bb(m2from, m2to) & m1to) && pos.see_sign(first) >= 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.