const Score KingProtector[] = { S(3, 5), S(4, 3), S(3, 0), S(1, -1) };
// Assorted bonuses and penalties
- const Score BishopPawns = S( 8, 12);
- const Score CloseEnemies = S( 7, 0);
- const Score Hanging = S( 52, 30);
- const Score HinderPassedPawn = S( 8, 1);
- const Score LongRangedBishop = S( 22, 0);
- const Score MinorBehindPawn = S( 16, 0);
- const Score PawnlessFlank = S( 20, 80);
- const Score RookOnPawn = S( 8, 24);
- const Score ThreatByPawnPush = S( 47, 26);
- const Score ThreatByRank = S( 16, 3);
- const Score ThreatBySafePawn = S(175,168);
- const Score ThreatOnQueen = S( 42, 21);
- const Score TrappedBishopA1H1 = S( 50, 50);
- const Score TrappedRook = S( 92, 0);
- const Score WeakQueen = S( 50, 10);
- const Score WeakUnopposedPawn = S( 5, 25);
+ const Score BishopPawns = S( 8, 12);
+ const Score CloseEnemies = S( 7, 0);
+ const Score Connectivity = S( 3, 1);
+ const Score CorneredBishop = S( 50, 50);
+ const Score Hanging = S( 52, 30);
+ const Score HinderPassedPawn = S( 8, 1);
+ const Score KnightOnQueen = S( 21, 11);
+ const Score LongDiagonalBishop = S( 22, 0);
+ const Score MinorBehindPawn = S( 16, 0);
+ const Score PawnlessFlank = S( 20, 80);
+ const Score RookOnPawn = S( 8, 24);
+ const Score SliderOnQueen = S( 42, 21);
+ const Score ThreatByPawnPush = S( 47, 26);
+ const Score ThreatByRank = S( 16, 3);
+ const Score ThreatBySafePawn = S(175,168);
+ const Score TrappedRook = S( 92, 0);
+ const Score WeakQueen = S( 50, 10);
+ const Score WeakUnopposedPawn = S( 5, 25);
#undef S
// attackedBy[color][piece type] is a bitboard representing all squares
// attacked by a given color and piece type. Special "piece types" which
- // are also calculated are QUEEN_DIAGONAL and ALL_PIECES.
+ // is also calculated is ALL_PIECES.
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
// which attack a square in the kingRing of the enemy king.
int kingAttackersCount[COLOR_NB];
- // kingAttackersWeight[color] is the sum of the "weights" of the pieces of the
- // given color which attack a square in the kingRing of the enemy king. The
- // weights of the individual piece types are given by the elements in the
- // KingAttackWeights array.
+ // kingAttackersWeight[color] is the sum of the "weights" of the pieces of
+ // the given color which attack a square in the kingRing of the enemy king.
+ // The weights of the individual piece types are given by the elements in
+ // the KingAttackWeights array.
int kingAttackersWeight[COLOR_NB];
- // kingAdjacentZoneAttacksCount[color] is the number of attacks by the given
- // color to squares directly adjacent to the enemy king. Pieces which attack
- // more than one square are counted multiple times. For instance, if there is
+ // kingAttacksCount[color] is the number of attacks by the given color to
+ // squares directly adjacent to the enemy king. Pieces which attack more
+ // than one square are counted multiple times. For instance, if there is
// a white knight on g5 and black's king is on g8, this white knight adds 2
- // to kingAdjacentZoneAttacksCount[WHITE].
- int kingAdjacentZoneAttacksCount[COLOR_NB];
+ // to kingAttacksCount[WHITE].
+ int kingAttacksCount[COLOR_NB];
};
kingRing[Us] |= shift<Up>(kingRing[Us]);
kingAttackersCount[Them] = popcount(attackedBy[Us][KING] & pe->pawn_attacks(Them));
- kingAdjacentZoneAttacksCount[Them] = kingAttackersWeight[Them] = 0;
+ kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
}
else
kingRing[Us] = kingAttackersCount[Them] = 0;
attackedBy[Us][Pt] = 0;
- if (Pt == QUEEN)
- attackedBy[Us][QUEEN_DIAGONAL] = 0;
-
while ((s = *pl++) != SQ_NONE)
{
// Find attacked squares, including x-ray attacks for bishops and rooks
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
: pos.attacks_from<Pt>(s);
- if (pos.pinned_pieces(Us) & s)
+ if (pos.blockers_for_king(Us) & s)
b &= LineBB[pos.square<KING>(Us)][s];
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
attackedBy[Us][Pt] |= b;
attackedBy[Us][ALL_PIECES] |= b;
- if (Pt == QUEEN)
- attackedBy[Us][QUEEN_DIAGONAL] |= b & PseudoAttacks[BISHOP][s];
-
if (b & kingRing[Them])
{
kingAttackersCount[Us]++;
kingAttackersWeight[Us] += KingAttackWeights[Pt];
- kingAdjacentZoneAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
+ kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
}
int mob = popcount(b & mobilityArea[Us]);
// Bonus for bishop on a long diagonal which can "see" both center squares
if (more_than_one(Center & (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) | s)))
- score += LongRangedBishop;
+ score += LongDiagonalBishop;
}
// An important Chess960 pattern: A cornered bishop blocked by a friendly
{
Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
- score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
- : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
- : TrappedBishopA1H1;
+ score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4
+ : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2
+ : CorneredBishop;
}
}
if (Pt == QUEEN)
{
// Penalty if any relative pin or discovered attack against the queen
- Bitboard pinners;
- if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, pinners))
+ Bitboard queenPinners;
+ if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners))
score -= WeakQueen;
}
}
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
const Square ksq = pos.square<KING>(Us);
- Bitboard weak, b, b1, b2, safe, unsafeChecks;
+ Bitboard weak, b, b1, b2, safe, unsafeChecks, pinned;
// King shelter and enemy pawns storm
Score score = pe->king_safety<Us>(pos, ksq);
// Main king safety evaluation
if (kingAttackersCount[Them] > 1 - pos.count<QUEEN>(Them))
{
- int kingDanger = unsafeChecks = 0;
+ int kingDanger = 0;
+ unsafeChecks = 0;
// Attacked squares defended at most once by our queen or king
weak = attackedBy[Them][ALL_PIECES]
// Unsafe or occupied checking squares will also be considered, as long as
// the square is in the attacker's mobility area.
unsafeChecks &= mobilityArea[Them];
+ pinned = pos.blockers_for_king(Us) & pos.pieces(Us);
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 102 * kingAdjacentZoneAttacksCount[Them]
+ + 102 * kingAttacksCount[Them]
+ 191 * popcount(kingRing[Us] & weak)
- + 143 * popcount(pos.pinned_pieces(Us) | unsafeChecks)
+ + 143 * popcount(pinned | unsafeChecks)
- 848 * !pos.count<QUEEN>(Them)
- 9 * mg_value(score) / 8
+ 40;
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
}
}
- // Penalty when our king is on a pawnless flank
- if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)]))
- score -= PawnlessFlank;
- // King tropism: firstly, find attacked squares in our king flank
- b = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
+ Bitboard kf = KingFlank[file_of(ksq)];
- assert(((Us == WHITE ? b << 4 : b >> 4) & b) == 0);
- assert(popcount(Us == WHITE ? b << 4 : b >> 4) == popcount(b));
+ // Penalty when our king is on a pawnless flank
+ if (!(pos.pieces(PAWN) & kf))
+ score -= PawnlessFlank;
- // Secondly, add the squares which are attacked twice in that flank and
- // which are not defended by our pawns.
- b = (Us == WHITE ? b << 4 : b >> 4)
- | (b & attackedBy2[Them] & ~attackedBy[Us][PAWN]);
+ // Find the squares that opponent attacks in our king flank, and the squares
+ // which are attacked twice in that flank but not defended by our pawns.
+ b1 = attackedBy[Them][ALL_PIECES] & kf & Camp;
+ b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN];
- score -= CloseEnemies * popcount(b);
+ // King tropism, to anticipate slow motion attacks on our king
+ score -= CloseEnemies * (popcount(b1) + popcount(b2));
if (T)
Trace::add(KING, Us, score);
template<Tracing T> template<Color Us>
Score Evaluation<T>::threats() const {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Direction Up = (Us == WHITE ? NORTH : SOUTH);
- const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
- const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
- const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safeThreats;
Score score = SCORE_ZERO;
b = pos.pieces(Us, PAWN)
& (~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]);
- safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
+ safeThreats = pawn_attacks_bb<Us>(b) & weak;
score += ThreatBySafePawn * popcount(safeThreats);
}
& (attackedBy[Us][ALL_PIECES] | ~attackedBy[Them][ALL_PIECES]);
// Bonus for safe pawn threats on the next move
- b = (shift<Left>(b) | shift<Right>(b))
+ b = pawn_attacks_bb<Us>(b)
& pos.pieces(Them)
& ~attackedBy[Us][PAWN];
score += ThreatByPawnPush * popcount(b);
- // Bonus for safe slider threats on the next move toward enemy queen
- safeThreats = ~pos.pieces(Us) & ~attackedBy2[Them] & attackedBy2[Us];
- b = (attackedBy[Us][BISHOP] & attackedBy[Them][QUEEN_DIAGONAL])
- | (attackedBy[Us][ROOK ] & attackedBy[Them][QUEEN] & ~attackedBy[Them][QUEEN_DIAGONAL]);
+ // Bonus for threats on the next moves against enemy queen
+ if (pos.count<QUEEN>(Them) == 1)
+ {
+ Square s = pos.square<QUEEN>(Them);
+ safeThreats = mobilityArea[Us] & ~stronglyProtected;
- score += ThreatOnQueen * popcount(b & safeThreats);
+ b = attackedBy[Us][KNIGHT] & pos.attacks_from<KNIGHT>(s);
+
+ score += KnightOnQueen * popcount(b & safeThreats);
+
+ b = (attackedBy[Us][BISHOP] & pos.attacks_from<BISHOP>(s))
+ | (attackedBy[Us][ROOK ] & pos.attacks_from<ROOK >(s));
+
+ score += SliderOnQueen * popcount(b & safeThreats & attackedBy2[Us]);
+ }
+
+ // Connectivity: ensure that knights, bishops, rooks, and queens are protected
+ b = (pos.pieces(Us) ^ pos.pieces(Us, PAWN, KING)) & attackedBy[Us][ALL_PIECES];
+ score += Connectivity * popcount(b);
if (T)
Trace::add(THREAT, Us, score);
behind |= (Us == WHITE ? behind >> 8 : behind << 8);
behind |= (Us == WHITE ? behind >> 16 : behind << 16);
- // Since SpaceMask[Us] is fully on our half of the board...
- assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0);
-
- // ...count safe + (behind & safe) with a single popcount.
- int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
+ int bonus = popcount(safe) + popcount(behind & safe);
int weight = pos.count<ALL_PIECES>(Us) - 2 * pe->open_files();
+
Score score = make_score(bonus * weight * weight / 16, 0);
if (T)
+ 8 * pe->pawn_asymmetry()
+ 12 * pos.count<PAWN>()
+ 16 * pawnsOnBothFlanks
+ + 48 * !pos.non_pawn_material()
-136 ;
// Now apply the bonus: note that we find the attacking side by extracting
Trace::add(TOTAL, score);
}
- return pos.side_to_move() == WHITE ? v : -v; // Side to move point of view
+ return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view
+ + Eval::Tempo;
}
} // namespace
/// evaluation of the position from the point of view of the side to move.
Value Eval::evaluate(const Position& pos) {
- return Evaluation<NO_TRACE>(pos).value() + Eval::Tempo;
+ return Evaluation<NO_TRACE>(pos).value();
}
Eval::Contempt = SCORE_ZERO; // Reset any dynamic contempt
- Value v = Evaluation<TRACE>(pos).value() + Eval::Tempo;
+ Value v = Evaluation<TRACE>(pos).value();
v = pos.side_to_move() == WHITE ? v : -v; // Trace scores are from white's point of view