// KingAttackWeights[PieceType] contains king attack weights by piece type
constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
- // Penalties for enemy's safe checks
- constexpr int QueenSafeCheck = 772;
- constexpr int RookSafeCheck = 1084;
- constexpr int BishopSafeCheck = 645;
- constexpr int KnightSafeCheck = 792;
+ // SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
+ // higher if multiple safe checks are possible for that piece type.
+ constexpr int SafeCheck[][2] = {
+ {}, {}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119}
+ };
#define S(mg, eg) make_score(mg, eg)
S(110,182), S(114,182), S(114,192), S(116,219) }
};
+ // KingProtector[knight/bishop] contains penalty for each distance unit to own king
+ constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
+
+ // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
+ // pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
+ constexpr Score Outpost[] = { S(56, 36), S(30, 23) };
+
+ // PassedRank[Rank] contains a bonus according to the rank of a passed pawn
+ constexpr Score PassedRank[RANK_NB] = {
+ S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
+ };
+
// RookOnFile[semiopen/open] contains bonuses for each rook when there is
// no (friendly) pawn on the rook file.
constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) };
S(0, 0), S(3, 46), S(37, 68), S(42, 60), S(0, 38), S(58, 41)
};
- // PassedRank[Rank] contains a bonus according to the rank of a passed pawn
- constexpr Score PassedRank[RANK_NB] = {
- S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
- };
-
// Assorted bonuses and penalties
- constexpr Score BishopPawns = S( 3, 7);
constexpr Score BishopOnKingRing = S( 24, 0);
+ constexpr Score BishopPawns = S( 3, 7);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
- constexpr Score BishopKingProtector = S( 6, 9);
- constexpr Score KnightKingProtector = S( 8, 9);
constexpr Score KnightOnQueen = S( 16, 11);
constexpr Score LongDiagonalBishop = S( 45, 0);
constexpr Score MinorBehindPawn = S( 18, 3);
- constexpr Score KnightOutpost = S( 56, 36);
- constexpr Score BishopOutpost = S( 30, 23);
- constexpr Score ReachableOutpost = S( 31, 22);
constexpr Score PassedFile = S( 11, 8);
constexpr Score PawnlessFlank = S( 17, 95);
+ constexpr Score QueenInfiltration = S( -2, 14);
+ constexpr Score ReachableOutpost = S( 31, 22);
constexpr Score RestrictedPiece = S( 7, 7);
constexpr Score RookOnKingRing = S( 16, 0);
- constexpr Score RookOnQueenFile = S( 5, 9);
- constexpr Score SliderOnQueen = S( 59, 18);
+ constexpr Score RookOnQueenFile = S( 6, 11);
+ constexpr Score SliderOnQueen = S( 60, 18);
constexpr Score ThreatByKing = S( 24, 89);
constexpr Score ThreatByPawnPush = S( 48, 39);
constexpr Score ThreatBySafePawn = S(173, 94);
constexpr Score TrappedRook = S( 55, 13);
- constexpr Score WeakQueen = S( 51, 14);
- constexpr Score WeakQueenProtection = S( 15, 0);
+ constexpr Score WeakQueenProtection = S( 14, 0);
+ constexpr Score WeakQueen = S( 56, 15);
+
#undef S
// Evaluation::initialize() computes king and pawn attacks, and the king ring
// bitboard for a given color. This is done at the beginning of the evaluation.
+
template<Tracing T> template<Color Us>
void Evaluation<T>::initialize() {
// Evaluation::pieces() scores pieces of a given color and type
+
template<Tracing T> template<Color Us, PieceType Pt>
Score Evaluation<T>::pieces() {
// Bonus if piece is on an outpost square or can reach one
bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them);
if (bb & s)
- score += (Pt == KNIGHT) ? KnightOutpost : BishopOutpost;
+ score += Outpost[Pt == BISHOP];
else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
score += ReachableOutpost;
score += MinorBehindPawn;
// Penalty if the piece is far from the king
- score -= (Pt == KNIGHT ? KnightKingProtector
- : BishopKingProtector) * distance(pos.square<KING>(Us), s);
+ score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
if (Pt == BISHOP)
{
Bitboard queenPinners;
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners))
score -= WeakQueen;
+
+ // Bonus for queen on weak square in enemy camp
+ if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s))
+ score += QueenInfiltration;
}
}
if (T)
// Evaluation::king() assigns bonuses and penalties to a king of a given color
+
template<Tracing T> template<Color Us>
Score Evaluation<T>::king() const {
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
// Enemy rooks checks
- rookChecks = b1 & safe & attackedBy[Them][ROOK];
+ rookChecks = b1 & attackedBy[Them][ROOK] & safe;
if (rookChecks)
- kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 175/100
- : RookSafeCheck;
+ kingDanger += SafeCheck[ROOK][more_than_one(rookChecks)];
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;
+ // Enemy queen safe checks: count them only if the checks are from squares from
+ // which opponent cannot 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
+ kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
+
+ // Enemy bishops checks: count them only if they are from squares from which
+ // opponent cannot 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;
+ kingDanger += SafeCheck[BISHOP][more_than_one(bishopChecks)];
+
else
unsafeChecks |= b2 & attackedBy[Them][BISHOP];
// Enemy knights checks
knightChecks = attacks_bb<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (knightChecks & safe)
- kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100
- : KnightSafeCheck;
+ kingDanger += SafeCheck[KNIGHT][more_than_one(knightChecks & safe)];
else
unsafeChecks |= knightChecks;
b2 = b1 & attackedBy2[Them];
b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
- int kingFlankAttack = popcount(b1) + popcount(b2);
+ int kingFlankAttack = popcount(b1) + popcount(b2);
int kingFlankDefense = popcount(b3);
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
// Evaluation::threats() assigns bonuses according to the types of the
// attacking and the attacked pieces.
+
template<Tracing T> template<Color Us>
Score Evaluation<T>::threats() const {
// Evaluation::winnable() adjusts the mg and eg score components based on the
- // known attacking/defending status of the players.
- // A single value is derived from the mg and eg values and returned.
+ // known attacking/defending status of the players. A single value is derived
+ // by interpolation from the mg and eg values and returned.
template<Tracing T>
Value Evaluation<T>::winnable(Score score) const {
bool almostUnwinnable = outflanking < 0
&& !pawnsOnBothFlanks;
- bool infiltration = rank_of(pos.square<KING>(WHITE)) > RANK_4
- || rank_of(pos.square<KING>(BLACK)) < RANK_5;
+ bool infiltration = rank_of(pos.square<KING>(WHITE)) > RANK_4
+ || rank_of(pos.square<KING>(BLACK)) < RANK_5;
// Compute the initiative bonus for the attacking side
int complexity = 9 * pe->passed_count()
eg += v;
// Compute the scale factor for the winning side
-
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
int sf = me->scale_factor(pos, strongSide);
else
sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
}
+ else if ( pos.non_pawn_material(WHITE) == RookValueMg
+ && pos.non_pawn_material(BLACK) == RookValueMg
+ && pos.count<PAWN>(strongSide) - pos.count<PAWN>(~strongSide) <= 1
+ && bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN))
+ && (attacks_bb<KING>(pos.square<KING>(~strongSide)) & pos.pieces(~strongSide, PAWN)))
+ sf = 36;
+ else if (pos.count<QUEEN>() == 1)
+ sf = 37 + 3 * (pos.count<QUEEN>(WHITE) == 1 ? pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK)
+ : pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE));
else
sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
}
return pos.side_to_move() == WHITE ? v : -v;
// Main evaluation begins here
-
initialize<WHITE>();
initialize<BLACK>();
// Pieces evaluated first (also populates attackedBy, attackedBy2).
- // Note that the order of evaluation of the terms is left unspecified
+ // Note that the order of evaluation of the terms is left unspecified.
score += pieces<WHITE, KNIGHT>() - pieces<BLACK, KNIGHT>()
+ pieces<WHITE, BISHOP>() - pieces<BLACK, BISHOP>()
+ pieces<WHITE, ROOK >() - pieces<BLACK, ROOK >()