constexpr Value SpaceThreshold = Value(12222);
// KingAttackWeights[PieceType] contains king attack weights by piece type
- constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
+ constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10, 40 };
// Penalties for enemy's safe checks
- constexpr int QueenSafeCheck = 780;
- constexpr int RookSafeCheck = 1078;
- constexpr int BishopSafeCheck = 635;
- constexpr int KnightSafeCheck = 790;
+ constexpr int QueenSafeCheck = 772;
+ constexpr int RookSafeCheck = 1084;
+ constexpr int BishopSafeCheck = 645;
+ constexpr int KnightSafeCheck = 792;
+
+ constexpr int OtherSafeCheck = 600;
+
#define S(mg, eg) make_score(mg, eg)
// MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game,
score += MinorBehindPawn;
// Penalty if the piece is far from the king
+ if (pos.count<KING>(Us))
- score -= KingProtector * distance(pos.square<KING>(Us), s);
+ score -= (Pt == KNIGHT ? KnightKingProtector
+ : BishopKingProtector) * distance(pos.square<KING>(Us), s);
if (Pt == BISHOP)
{
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
- // Enemy rooks checks
- rookChecks = b1 & safe & attackedBy[Them][ROOK];
- if (rookChecks)
- kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 175/100
- : RookSafeCheck;
- else
- unsafeChecks |= b1 & attackedBy[Them][ROOK];
-
- // Enemy queen safe checks: we count them only if they are from squares from
- // which we can't give a rook check, because rook checks are more valuable.
- queenChecks = (b1 | b2)
- & attackedBy[Them][QUEEN]
- & safe
- & ~attackedBy[Us][QUEEN]
- & ~rookChecks;
- if (queenChecks)
- kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100
- : QueenSafeCheck;
-
- // Enemy bishops checks: we count them only if they are from squares from
- // which we can't give a queen check, because queen checks are more valuable.
- bishopChecks = b2
- & attackedBy[Them][BISHOP]
- & safe
- & ~queenChecks;
- if (bishopChecks)
- kingDanger += more_than_one(bishopChecks) ? BishopSafeCheck * 3/2
- : BishopSafeCheck;
- else
- unsafeChecks |= b2 & attackedBy[Them][BISHOP];
+ std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
+ return attackedBy[c][pt] | (pos.piece_drops() && pos.count_in_hand(c, pt) ? pos.drop_region(c, pt) & ~pos.pieces() : Bitboard(0));
+ };
+ for (PieceType pt : pos.piece_types())
+ {
+ switch (pt)
+ {
+ case QUEEN:
+ // Enemy queen safe checks: we count them only if they are from squares from
+ // which we can't give a rook check, because rook checks are more valuable.
+ queenChecks = (b1 | b2)
+ & get_attacks(Them, QUEEN)
+ & pos.board_bb()
+ & safe
+ & ~attackedBy[Us][QUEEN]
+ & ~(b1 & attackedBy[Them][ROOK]);
+
+ if (queenChecks)
- kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2
++ kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100
+ : QueenSafeCheck;
+ break;
+ case ROOK:
+ case BISHOP:
+ case KNIGHT:
+ knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
+ if (knightChecks & safe)
- kingDanger += (pt == ROOK ? RookSafeCheck
- : pt == BISHOP ? BishopSafeCheck
- : KnightSafeCheck) * (more_than_one(knightChecks & safe) ? 3 : 2) / 2;
++ kingDanger += pt == ROOK ? RookSafeCheck * (more_than_one(knightChecks & safe) ? 175 : 100) / 100
++ : pt == BISHOP ? BishopSafeCheck * (more_than_one(knightChecks & safe) ? 150 : 100) / 100
++ : KnightSafeCheck * (more_than_one(knightChecks & safe) ? 162 : 100) / 100;
+ else
+ unsafeChecks |= knightChecks;
+ break;
+ case PAWN:
+ if (pos.piece_drops() && pos.count_in_hand(Them, pt))
+ {
+ pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
+ if (pawnChecks & safe)
+ kingDanger += OtherSafeCheck;
+ else
+ unsafeChecks |= pawnChecks;
+ }
+ break;
+ case SHOGI_PAWN:
+ case KING:
+ break;
+ default:
+ otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
+ if (otherChecks & safe)
+ kingDanger += OtherSafeCheck * (more_than_one(otherChecks & safe) ? 3 : 2) / 2;
+ else
+ unsafeChecks |= otherChecks;
+ }
+ }
- // Enemy knights checks
- knightChecks = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
- if (knightChecks & safe)
- kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100
- : KnightSafeCheck;
- else
- unsafeChecks |= knightChecks;
+ // Virtual piece drops
+ if (pos.two_boards() && pos.piece_drops())
+ {
+ for (PieceType pt : pos.piece_types())
+ if (!pos.count_in_hand(Them, pt) && (attacks_bb(Us, pt, ksq, pos.pieces()) & safe & pos.drop_region(Them, pt) & ~pos.pieces()))
+ {
+ kingDanger += OtherSafeCheck * 500 / (500 + PieceValue[MG][pt]);
+ // Presumably a mate threat
+ if (!(attackedBy[Us][KING] & ~(attackedBy[Them][ALL_PIECES] | pos.pieces(Us))))
+ kingDanger += 2000;
+ }
+ }
+
+ if (pos.check_counting())
+ kingDanger += kingDanger * 7 / (3 + pos.checks_remaining(Them));
+
+ Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq;
+ Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s);
// Find the squares that opponent attacks in our king flank, the squares
// which they attack twice in that flank, and the squares that we defend.