// 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). private static bool refutes(Position pos, int move, int threat) { Debug.Assert(Utils.is_ok_M(move)); Debug.Assert(Utils.is_ok_M(threat)); Square mfrom = Utils.from_sq(move); Square mto = Utils.to_sq(move); Square tfrom = Utils.from_sq(threat); Square tto = Utils.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) && (Position.PieceValue[PhaseC.MG][pos.piece_on(tfrom)] >= Position.PieceValue[PhaseC.MG][pos.piece_on(tto)] || Utils.type_of(pos.piece_on(tfrom)) == PieceTypeC.KING)) { // Update occupancy as if the piece and the threat are moving var occ = Utils.xor_bit(Utils.xor_bit(Utils.xor_bit(pos.occupied_squares, mfrom), mto), tfrom); Piece piece = pos.piece_on(mfrom); // The piece moved in 'to' attacks the square 's' ? if (Utils.bit_is_set(Position.attacks_from(piece, mto, occ), tto) != 0) { return true; } // Scan for possible X-ray attackers behind the moved piece var xray = (Utils.rook_attacks_bb(tto, occ) & pos.pieces(PieceTypeC.ROOK, PieceTypeC.QUEEN, Utils.color_of(piece))) | (Utils.bishop_attacks_bb(tto, occ) & pos.pieces(PieceTypeC.BISHOP, PieceTypeC.QUEEN, Utils.color_of(piece))); // Verify attackers are triggered by our move and not already existing if ((xray != 0) && ((xray ^ (xray & pos.attacks_from_QUEEN(tto))) != 0)) { return true; } } // Don't prune safe moves which block the threat path if ((Utils.bit_is_set(Utils.between_bb(tfrom, tto), mto) != 0) && pos.see(move, true) >= 0) { return true; } return false; }