enum Tracing { NO_TRACE, TRACE };
enum Term { // The first 8 entries are reserved for PieceType
- MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB
+ MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB
};
Score scores[TERM_NB][COLOR_NB];
std::ostream& operator<<(std::ostream& os, Term t) {
- if (t == MATERIAL || t == IMBALANCE || t == INITIATIVE || t == TOTAL)
+ if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL)
os << " ---- ----" << " | " << " ---- ----";
else
os << scores[t][WHITE] << " | " << scores[t][BLACK];
};
// Assorted bonuses and penalties
+ constexpr Score BishopKingProtector = S( 6, 9);
+ constexpr Score BishopOnKingRing = S( 24, 0);
+ constexpr Score BishopOutpost = S( 30, 23);
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 KnightOutpost = S( 56, 36);
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
template<Color Us> Score threats() const;
template<Color Us> Score passed() const;
template<Color Us> Score space() const;
- ScaleFactor scale_factor(Value eg) const;
- Score initiative(Score score) const;
+ Value winnable(Score score) const;
const Position& pos;
Material::Entry* me;
// 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() {
: attacks_bb<Pt>(s, pos.pieces());
if (pos.blockers_for_king(Us) & s)
- b &= LineBB[pos.square<KING>(Us)][s];
+ b &= line_bb(pos.square<KING>(Us), s);
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
attackedBy[Us][Pt] |= b;
kingAttackersWeight[Us] += KingAttackWeights[Pt];
kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
}
+
else if (Pt == ROOK && (file_bb(s) & kingRing[Them]))
score += RookOnKingRing;
+ else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
+ score += BishopOnKingRing;
+
int mob = popcount(b & mobilityArea[Us]);
mobility[Us] += MobilityBonus[Pt - 2][mob];
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 {
// 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::space() computes the space evaluation for a given side. The
- // space evaluation is a simple bonus based on the number of safe squares
- // available for minor pieces on the central four files on ranks 2--4. Safe
- // squares one, two or three squares behind a friendly pawn are counted
- // twice. Finally, the space bonus is multiplied by a weight. The aim is to
- // improve play on game opening.
+ // Evaluation::space() computes a space evaluation for a given side, aiming to improve game
+ // play in the opening. It is based on the number of safe squares on the 4 central files
+ // on ranks 2 to 4. Completely safe squares behind a friendly pawn are counted twice.
+ // Finally, the space bonus is multiplied by a weight which decreases according to occupancy.
template<Tracing T> template<Color Us>
Score Evaluation<T>::space() const {
+ // Early exit if, for example, both queens or 6 minor pieces have been exchanged
if (pos.non_pawn_material() < SpaceThreshold)
return SCORE_ZERO;
}
- // Evaluation::initiative() computes the initiative correction value
- // for the position. It is a second order bonus/malus based on the
- // known attacking/defending status of the players.
+ // Evaluation::winnable() adjusts the mg and eg score components based on the
+ // 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>
- Score Evaluation<T>::initiative(Score score) const {
+ Value Evaluation<T>::winnable(Score score) const {
int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
- distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
+ 24 * infiltration
+ 51 * !pos.non_pawn_material()
- 43 * almostUnwinnable
- - 2 * pos.rule50_count()
-110 ;
Value mg = mg_value(score);
int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0);
int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg));
- if (T)
- Trace::add(INITIATIVE, make_score(u, v));
+ mg += u;
+ eg += v;
- return make_score(u, v);
- }
-
-
- // Evaluation::scale_factor() computes the scale factor for the winning side
-
- template<Tracing T>
- ScaleFactor Evaluation<T>::scale_factor(Value eg) const {
+ // 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
+ && !pe->passed_pawns(strongSide)
+ && 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
sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
}
- return ScaleFactor(sf);
+ // Interpolate between the middlegame and (scaled by 'sf') endgame score
+ v = mg * int(me->game_phase())
+ + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL;
+ v /= PHASE_MIDGAME;
+
+ if (T)
+ {
+ Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score)));
+ Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL));
+ }
+
+ return Value(v);
}
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 >()
+ passed< WHITE>() - passed< BLACK>()
+ space< WHITE>() - space< BLACK>();
- score += initiative(score);
-
- // Interpolate between a middlegame and a (scaled by 'sf') endgame score
- ScaleFactor sf = scale_factor(eg_value(score));
- v = mg_value(score) * int(me->game_phase())
- + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL;
-
- v /= PHASE_MIDGAME;
+ // Derive single value from mg and eg parts of score
+ v = winnable(score);
// In case of tracing add all remaining individual evaluation terms
if (T)
Trace::add(IMBALANCE, me->imbalance());
Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK));
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
- Trace::add(TOTAL, score);
}
+ // Evaluation grain
+ v = (v / 16) * 16;
+
// Side to move point of view
- return (pos.side_to_move() == WHITE ? v : -v) + Tempo;
+ v = (pos.side_to_move() == WHITE ? v : -v) + Tempo;
+
+ // Damp down the evaluation linearly when shuffling
+ v = v * (100 - pos.rule50_count()) / 100;
+
+ return v;
}
} // namespace
<< " Threats | " << Term(THREAT)
<< " Passed | " << Term(PASSED)
<< " Space | " << Term(SPACE)
- << " Initiative | " << Term(INITIATIVE)
+ << " Winnable | " << Term(WINNABLE)
<< " ------------+-------------+-------------+------------\n"
<< " Total | " << Term(TOTAL);
- ss << "\nTotal evaluation: " << to_cp(v) << " (white side)\n";
+ ss << "\nFinal evaluation: " << to_cp(v) << " (white side)\n";
return ss.str();
}