- // KingDanger[Color][attackUnits] contains the actual king danger weighted
- // scores, indexed by color and by a calculated integer number.
- Score KingDanger[COLOR_NB][128];
-
- // Function prototypes
- template<bool Trace>
- Value do_evaluate(const Position& pos);
-
- template<Color Us>
- void init_eval_info(const Position& pos, EvalInfo& ei);
-
- template<PieceType Pt, Color Us, bool Trace>
- Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea);
-
- template<Color Us, bool Trace>
- Score evaluate_king(const Position& pos, const EvalInfo& ei);
-
- template<Color Us, bool Trace>
- Score evaluate_threats(const Position& pos, const EvalInfo& ei);
-
- template<Color Us, bool Trace>
- Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei);
-
- template<Color Us>
- int evaluate_space(const Position& pos, const EvalInfo& ei);
-
- Score evaluate_unstoppable_pawns(const Position& pos, Color us, const EvalInfo& ei);
-
- Value interpolate(const Score& v, Phase ph, ScaleFactor sf);
- Score apply_weight(Score v, const Weight& w);
- Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
-}
-
-
-namespace Eval {
-
- /// evaluate() is the main evaluation function. It always computes two
- /// values, an endgame score and a middlegame score, and interpolates
- /// between them based on the remaining material.
-
- Value evaluate(const Position& pos) {
- return do_evaluate<false>(pos);
- }
-
-
- /// 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);
- }
-
-
- /// init() computes evaluation weights from the corresponding UCI parameters
- /// and setup king tables.
-
- void init() {
-
- Weights[Mobility] = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[Mobility]);
- Weights[PawnStructure] = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
- Weights[PassedPawns] = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
- Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]);
- Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
- Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
-
- const int MaxSlope = 30;
- const int Peak = 1280;
-
- for (int t = 0, i = 1; i < 100; ++i)
- {
- t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));
-
- KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
- KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
- }
- }
-
-} // namespace Eval
-
-
-namespace {
-
-template<bool Trace>
-Value do_evaluate(const Position& pos) {
-
- assert(!pos.checkers());
-
- EvalInfo ei;
- Score score, mobility[2] = { SCORE_ZERO, SCORE_ZERO };
- Thread* thisThread = pos.this_thread();
-
- // Initialize score by reading the incrementally updated scores included
- // 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);
-
- // Probe the material hash table
- ei.mi = Material::probe(pos, thisThread->materialTable, thisThread->endgames);
- score += ei.mi->material_value();
-
- // If we have a specialized evaluation function for the current material
- // configuration, call it and return.
- if (ei.mi->specialized_eval_exists())
- return ei.mi->evaluate(pos);
-
- // Probe the pawn hash table
- ei.pi = Pawns::probe(pos, thisThread->pawnsTable);
- score += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
-
- // Initialize attack and king safety bitboards
- init_eval_info<WHITE>(pos, ei);
- init_eval_info<BLACK>(pos, ei);
-
- ei.attackedBy[WHITE][ALL_PIECES] |= ei.attackedBy[WHITE][KING];
- ei.attackedBy[BLACK][ALL_PIECES] |= ei.attackedBy[BLACK][KING];
-
- // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
- Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | pos.pieces(WHITE, PAWN, KING)),
- ~(ei.attackedBy[WHITE][PAWN] | pos.pieces(BLACK, PAWN, KING)) };
-
- // Evaluate pieces and mobility
- score += evaluate_pieces<KNIGHT, WHITE, Trace>(pos, ei, mobility, mobilityArea);
- score += apply_weight(mobility[WHITE] - mobility[BLACK], Weights[Mobility]);
-
- // 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)
- - evaluate_king<BLACK, Trace>(pos, ei);
-
- // Evaluate tactical threats, we need full attack information including king
- score += evaluate_threats<WHITE, Trace>(pos, ei)
- - evaluate_threats<BLACK, Trace>(pos, ei);
-
- // Evaluate passed pawns, we need full attack information including king
- score += evaluate_passed_pawns<WHITE, Trace>(pos, ei)
- - evaluate_passed_pawns<BLACK, Trace>(pos, ei);
-
- // If one side has only a king, score for potential unstoppable pawns
- if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK))
- score += evaluate_unstoppable_pawns(pos, WHITE, ei)
- - evaluate_unstoppable_pawns(pos, BLACK, ei);
-
- // Evaluate space for both sides, only in middlegame
- if (ei.mi->space_weight())
- {
- int s = evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei);
- score += apply_weight(s * ei.mi->space_weight(), Weights[Space]);
- }