// king is on g8 and there's a white knight on g5, this knight adds
// 2 to kingAdjacentZoneAttacksCount[BLACK].
int kingAdjacentZoneAttacksCount[COLOR_NB];
+
+ Bitboard pinnedPieces[COLOR_NB];
};
// Evaluation grain size, must be a power of 2
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41) }
};
- // Outpost[PieceType][Square] contains bonuses of knights and bishops, indexed
- // by piece type and square (from white's point of view).
+ // Outpost[PieceType][Square] contains bonuses for knights and bishops outposts,
+ // indexed by piece type and square (from white's point of view).
const Value Outpost[][SQUARE_NB] = {
{
// A B C D E F G H
const Score RookOpenFile = make_score(43, 21);
const Score RookSemiopenFile = make_score(19, 10);
const Score BishopPawns = make_score( 8, 12);
+ const Score KnightPawns = make_score( 8, 4);
const Score MinorBehindPawn = make_score(16, 0);
const Score UndefendedMinor = make_score(25, 10);
const Score TrappedRook = make_score(90, 0);
// Function prototypes
template<bool Trace>
- Value do_evaluate(const Position& pos, Value& margin);
+ Value do_evaluate(const Position& pos);
template<Color Us>
void init_eval_info(const Position& pos, EvalInfo& ei);
Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score* mobility);
template<Color Us, bool Trace>
- Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]);
+ Score evaluate_king(const Position& pos, const EvalInfo& ei);
template<Color Us, bool Trace>
Score evaluate_threats(const Position& pos, const EvalInfo& ei);
/// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material.
- Value evaluate(const Position& pos, Value& margin) {
- return do_evaluate<false>(pos, margin);
+ Value evaluate(const Position& pos) {
+ return do_evaluate<false>(pos);
}
- /// trace() is like evaluate() but instead of a value returns a string suitable
- /// to be print on stdout with the detailed descriptions and values of each
- /// evaluation term. Used mainly for debugging.
+ /// trace() is like evaluate(), but instead of returning a value, it returns
+ /// a string (suitable for outputting to stdout) that contains the detailed
+ /// descriptions and values of each evaluation term. It's mainly used for
+ /// debugging.
std::string trace(const Position& pos) {
return Tracing::do_trace(pos);
}
namespace {
template<bool Trace>
-Value do_evaluate(const Position& pos, Value& margin) {
+Value do_evaluate(const Position& pos) {
assert(!pos.checkers());
EvalInfo ei;
- Value margins[COLOR_NB];
Score score, mobility[2] = { SCORE_ZERO, SCORE_ZERO };
Thread* th = pos.this_thread();
- // margins[] store the uncertainty estimation of position's evaluation
- // that typically is used by the search for pruning decisions.
- margins[WHITE] = margins[BLACK] = VALUE_ZERO;
-
// Initialize score by reading the incrementally updated scores included
- // in the position object (material + piece square tables) and adding
+ // in the position object (material + piece square tables) and adding a
// Tempo bonus. Score is computed from the point of view of white.
score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo);
// If we have a specialized evaluation function for the current material
// configuration, call it and return.
if (ei.mi->specialized_eval_exists())
- {
- margin = VALUE_ZERO;
return ei.mi->evaluate(pos);
- }
// Probe the pawn hash table
ei.pi = Pawns::probe(pos, th->pawnsTable);
// Evaluate kings after all other pieces because we need complete attack
// information when computing the king safety evaluation.
- score += evaluate_king<WHITE, Trace>(pos, ei, margins)
- - evaluate_king<BLACK, Trace>(pos, ei, margins);
+ score += evaluate_king<WHITE, Trace>(pos, ei)
+ - evaluate_king<BLACK, Trace>(pos, ei);
// Evaluate tactical threats, we need full attack information including king
score += evaluate_threats<WHITE, Trace>(pos, ei)
&& pos.opposite_bishops()
&& sf == SCALE_FACTOR_NORMAL)
{
- // Only the two bishops ?
+ // Ignoring any pawns, do both sides only have a single bishop and no
+ // other pieces ?
if ( pos.non_pawn_material(WHITE) == BishopValueMg
&& pos.non_pawn_material(BLACK) == BishopValueMg)
{
sf = ScaleFactor(50);
}
- margin = margins[pos.side_to_move()];
Value v = interpolate(score, ei.mi->game_phase(), sf);
// In case of tracing add all single evaluation contributions for both white and black
Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
Tracing::add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
Tracing::add(TOTAL, score);
- Tracing::stream << "\nUncertainty margin: White: " << to_cp(margins[WHITE])
- << ", Black: " << to_cp(margins[BLACK])
- << "\nScaling: " << std::noshowpos
+ Tracing::stream << "\nScaling: " << std::noshowpos
<< std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, "
<< std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
<< std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
+ ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
+
Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.king_square(Them));
ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
}
- // evaluate_outposts() evaluates bishop and knight outposts squares
+ // evaluate_outposts() evaluates bishop and knight outpost squares
template<PieceType Piece, Color Us>
Score evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) {
: Piece == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
: pos.attacks_from<Piece>(s);
+ if (ei.pinnedPieces[Us] & s)
+ b &= LineBB[pos.king_square(Us)][s];
+
ei.attackedBy[Us][Piece] |= b;
if (b & ei.kingRing[Them])
ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
}
- int mob = popcount<Piece == QUEEN ? Full : Max15>(b & mobilityArea);
+ int mob = Piece != QUEEN ? popcount<Max15>(b & mobilityArea)
+ : popcount<Full >(b & mobilityArea);
+
mobility[Us] += MobilityBonus[Piece][mob];
- // Decrease score if we are attacked by an enemy pawn. Remaining part
+ // Decrease score if we are attacked by an enemy pawn. The remaining part
// of threat evaluation must be done later when we have full attack info.
if (ei.attackedBy[Them][PAWN] & s)
score -= ThreatenedByPawn[Piece];
if (Piece == BISHOP)
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
+ // Penalty for knight when there are few enemy pawns
+ if (Piece == KNIGHT)
+ score -= KnightPawns * std::max(5 - pos.count<PAWN>(Them), 0);
+
if (Piece == BISHOP || Piece == KNIGHT)
{
// Bishop and knight outposts squares
Square ksq = pos.king_square(Us);
- // Penalize rooks which are trapped inside a king. Penalize more if
- // king has lost right to castle.
+ // Penalize rooks which are trapped by a king. Penalize more if the
+ // king has lost its castling capability.
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
&& (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
&& !ei.pi->semiopen_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E))
// evaluate_king() assigns bonuses and penalties to a king of a given color
template<Color Us, bool Trace>
- Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]) {
+ Score evaluate_king(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
if ( ei.kingAttackersCount[Them] >= 2
&& ei.kingAdjacentZoneAttacksCount[Them])
{
- // Find the attacked squares around the king which has no defenders
+ // Find the attacked squares around the king which have no defenders
// apart from the king itself
undefended = ei.attackedBy[Them][ALL_PIECES]
& ei.attackedBy[Us][KING]
+ KingExposed[relative_square(Us, ksq)]
- mg_value(score) / 32;
- // Analyse enemy's safe queen contact checks. First find undefended
- // squares around the king attacked by enemy queen...
+ // Analyse the enemy's safe queen contact checks. Firstly, find the
+ // undefended squares around the king that are attacked by the enemy's
+ // queen...
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
if (b)
{
- // ...then remove squares not supported by another enemy piece
+ // ...and then remove squares not supported by another enemy piece
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
if (b)
* (Them == pos.side_to_move() ? 2 : 1);
}
- // Analyse enemy's safe rook contact checks. First find undefended
- // squares around the king attacked by enemy rooks...
+ // Analyse the enemy's safe rook contact checks. Firstly, find the
+ // undefended squares around the king that are attacked by the enemy's
+ // rooks...
b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces(Them);
- // Consider only squares where the enemy rook gives check
+ // Consider only squares where the enemy's rook gives check
b &= PseudoAttacks[ROOK][ksq];
if (b)
{
- // ...then remove squares not supported by another enemy piece
+ // ...and then remove squares not supported by another enemy piece
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
if (b)
* (Them == pos.side_to_move() ? 2 : 1);
}
- // Analyse enemy's safe distance checks for sliders and knights
+ // Analyse the enemy's safe distance checks for sliders and knights
safe = ~(pos.pieces(Them) | ei.attackedBy[Us][ALL_PIECES]);
b1 = pos.attacks_from<ROOK>(ksq) & safe;
attackUnits = std::min(99, std::max(0, attackUnits));
// Finally, extract the king danger score from the KingDanger[]
- // array and subtract the score from evaluation. Set also margins[]
- // value that will be used for pruning because this value can sometimes
- // be very big, and so capturing a single attacking piece can therefore
- // result in a score change far bigger than the value of the captured piece.
+ // array and subtract the score from evaluation.
score -= KingDanger[Us == Search::RootColor][attackUnits];
- margins[Us] += mg_value(KingDanger[Us == Search::RootColor][attackUnits]);
}
if (Trace)
Bitboard b, undefendedMinors, weakEnemies;
Score score = SCORE_ZERO;
- // Undefended minors get penalized even if not under attack
+ // Undefended minors get penalized even if they are not under attack
undefendedMinors = pos.pieces(Them, BISHOP, KNIGHT)
& ~ei.attackedBy[Them][ALL_PIECES];
// Add bonus according to type of attacked enemy piece and to the
// type of attacking piece, from knights to queens. Kings are not
- // considered because are already handled in king evaluation.
+ // considered because they are already handled in king evaluation.
if (weakEnemies)
for (PieceType pt1 = KNIGHT; pt1 < KING; ++pt1)
{
{
Square blockSq = s + pawn_push(Us);
- // Adjust bonus based on kings proximity
+ // Adjust bonus based on the king's proximity
ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 5 * rr)
- Value(square_distance(pos.king_square(Us ), blockSq) * 2 * rr);
if (relative_rank(Us, blockSq) != RANK_8)
ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr);
- // If the pawn is free to advance, increase bonus
+ // If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
{
squaresToQueen = forward_bb(Us, s);
else
defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
- // If there aren't enemy attacks huge bonus, a bit smaller if at
- // least block square is not attacked, otherwise smallest bonus.
+ // If there aren't any enemy attacks, then assign a huge bonus.
+ // The bonus will be a bit smaller if at least the block square
+ // isn't attacked, otherwise assign the smallest possible bonus.
int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 3;
- // Big bonus if the path to queen is fully defended, a bit less
- // if at least block square is defended.
+ // Assign a big bonus if the path to the queen is fully defended,
+ // otherwise assign a bit less of a bonus if at least the block
+ // square is defended.
if (defendedSquares == squaresToQueen)
k += 6;
ebonus -= ebonus / 4;
}
- // Increase the bonus if we have more non-pawn pieces
- if (pos.count<ALL_PIECES>( Us) - pos.count<PAWN>( Us) >
- pos.count<ALL_PIECES>(Them) - pos.count<PAWN>(Them))
+ if (pos.count<PAWN>(Us) < pos.count<PAWN>(Them))
ebonus += ebonus / 4;
score += make_score(mbonus, ebonus);
// evaluate_unstoppable_pawns() scores the most advanced among the passed and
// candidate pawns. In case opponent has no pieces but pawns, this is somewhat
- // related to the possibility pawns are unstoppable.
+ // related to the possibility that pawns are unstoppable.
Score evaluate_unstoppable_pawns(const Position& pos, Color us, const EvalInfo& ei) {
stream << std::showpoint << std::showpos << std::fixed << std::setprecision(2);
std::memset(scores, 0, 2 * (TOTAL + 1) * sizeof(Score));
- Value margin;
- do_evaluate<true>(pos, margin);
+ do_evaluate<true>(pos);
std::string totals = stream.str();
stream.str("");