+ Bitboard attacks(const Piece P, const Square sq, const Bitboard occ)
+ {
+ switch(P)
+ {
+ case WP:
+ case BP:
+ case WN:
+ case BN:
+ case WK:
+ case BK:
+ return StepAttackBB[P][sq];
+ case WB:
+ case BB:
+ return bishop_attacks_bb(sq, occ);
+ case WR:
+ case BR:
+ return rook_attacks_bb(sq, occ);
+ case WQ:
+ case BQ:
+ return bishop_attacks_bb(sq, occ) | rook_attacks_bb(sq, occ);
+ default:
+ assert(false);
+ return 0ULL;
+ }
+ }
+
+ bool check_is_useless(Position &pos, Move move, Value eval, Value futilityBase, Value beta, Value *bValue)
+ {
+ Value bestValue = *bValue;
+
+ /// Rule 1. Using checks to reposition pieces when close to beta
+ if (eval + PawnValueMidgame / 4 < beta)
+ {
+ if (eval + PawnValueMidgame / 4 > bestValue)
+ bestValue = eval + PawnValueMidgame / 4;
+ }
+ else
+ return false;
+
+ Square from = move_from(move);
+ Square to = move_to(move);
+ Color oppColor = opposite_color(pos.side_to_move());
+ Square oppKing = pos.king_square(oppColor);
+
+ Bitboard occ = pos.occupied_squares() & ~(1ULL << from) & ~(1ULL <<oppKing);
+ Bitboard oppOcc = pos.pieces_of_color(oppColor) & ~(1ULL <<oppKing);
+ Bitboard oldAtt = attacks(pos.piece_on(from), from, occ);
+ Bitboard newAtt = attacks(pos.piece_on(from), to, occ);
+
+ // Rule 2. Checks which give opponent's king at most one escape square are dangerous
+ Bitboard escapeBB = attacks(WK, oppKing, 0) & ~oppOcc & ~newAtt & ~(1ULL << to);
+
+ if (!escapeBB)
+ return false;
+
+ if (!(escapeBB & (escapeBB - 1)))
+ return false;
+
+ /// Rule 3. Queen contact check is very dangerous
+ if ( pos.type_of_piece_on(from) == QUEEN
+ && bit_is_set(attacks(WK, oppKing, 0), to))
+ return false;
+
+ /// Rule 4. Creating new double threats with checks
+ Bitboard newVictims = oppOcc & ~oldAtt & newAtt;
+
+ while(newVictims)
+ {
+ Square victimSq = pop_1st_bit(&newVictims);
+
+ Value futilityValue = futilityBase + pos.endgame_value_of_piece_on(victimSq);
+
+ // Note that here we generate illegal "double move"!
+ if (futilityValue >= beta && pos.see_sign(make_move(from, victimSq)) >= 0)
+ return false;
+
+ if (futilityValue > bestValue)
+ bestValue = futilityValue;
+ }
+
+ *bValue = bestValue;
+ return true;
+ }