- // SafetyTable[] contains the actual king safety scores. It is initialized
- // in init_safety().
- Value SafetyTable[100];
-
- // Pawn and material hash tables, indexed by the current thread id
- PawnInfoTable* PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- MaterialInfoTable* MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-
- // Sizes of pawn and material hash tables
- const int PawnTableSize = 16384;
- const int MaterialTableSize = 1024;
-
- // Function prototypes
- template<bool HasPopCnt>
- Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID);
-
- template<Color Us, bool HasPopCnt>
- void evaluate_pieces_of_color(const Position& pos, EvalInfo& ei);
-
- template<Color Us, bool HasPopCnt>
- void evaluate_king(const Position& pos, EvalInfo& ei);
-
- template<Color Us>
- void evaluate_threats(const Position& pos, EvalInfo& ei);
-
- template<Color Us, bool HasPopCnt>
- void evaluate_space(const Position& pos, EvalInfo& ei);
-
- void evaluate_passed_pawns(const Position& pos, EvalInfo& ei);
- void evaluate_trapped_bishop_a7h7(const Position& pos, Square s, Color us, EvalInfo& ei);
- void evaluate_trapped_bishop_a1h1(const Position& pos, Square s, Color us, EvalInfo& ei);
- inline Value apply_weight(Value v, int w);
- inline Score apply_weight(Score v, int wmg, int weg);
- Value scale_by_game_phase(const Score& v, Phase ph, const ScaleFactor sf[]);
- int weight_option(const std::string& opt, int weight);
- void init_safety();
-}
-
-
-////
-//// Functions
-////
-
-/// evaluate() is the main evaluation function. It always computes two
-/// values, an endgame score and a middle game score, and interpolates
-/// between them based on the remaining material.
-Value evaluate(const Position& pos, EvalInfo& ei, int threadID) {
-
- return CpuHasPOPCNT ? do_evaluate<true>(pos, ei, threadID)
- : do_evaluate<false>(pos, ei, threadID);
-}
-
-namespace {
-
-template<bool HasPopCnt>
-Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
-
- assert(pos.is_ok());
- assert(threadID >= 0 && threadID < THREAD_MAX);
- assert(!pos.is_check());
-
- memset(&ei, 0, sizeof(EvalInfo));
-
- // Initialize by reading the incrementally updated scores included in the
- // position object (material + piece square tables)
- ei.value = pos.value();
-
- // Probe the material hash table
- ei.mi = MaterialTable[threadID]->get_material_info(pos);
- ei.value += 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);
-
- // After get_material_info() call that modifies them
- ScaleFactor factor[2];
- factor[WHITE] = ei.mi->scale_factor(pos, WHITE);
- factor[BLACK] = ei.mi->scale_factor(pos, BLACK);
-
- // Probe the pawn hash table
- ei.pi = PawnTable[threadID]->get_pawn_info(pos);
- ei.value += apply_weight(ei.pi->value(), WeightPawnStructureMidgame, WeightPawnStructureEndgame);
-
- // Initialize king attack bitboards and king attack zones for both sides
- ei.attackedBy[WHITE][KING] = pos.attacks_from<KING>(pos.king_square(WHITE));
- ei.attackedBy[BLACK][KING] = pos.attacks_from<KING>(pos.king_square(BLACK));
- ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8);
- ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8);
-
- // Initialize pawn attack bitboards for both sides
- ei.attackedBy[WHITE][PAWN] = ei.pi->pawn_attacks(WHITE);
- ei.attackedBy[BLACK][PAWN] = ei.pi->pawn_attacks(BLACK);
- Bitboard b1 = ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING];
- Bitboard b2 = ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING];
- if (b1)
- ei.kingAttackersCount[WHITE] = count_1s_max_15<HasPopCnt>(b1)/2;
-
- if (b2)
- ei.kingAttackersCount[BLACK] = count_1s_max_15<HasPopCnt>(b2)/2;
-
- // Evaluate pieces
- evaluate_pieces_of_color<WHITE, HasPopCnt>(pos, ei);
- evaluate_pieces_of_color<BLACK, HasPopCnt>(pos, ei);
-
- // Kings. Kings are evaluated after all other pieces for both sides,
- // because we need complete attack information for all pieces when computing
- // the king safety evaluation.
- evaluate_king<WHITE, HasPopCnt>(pos, ei);
- evaluate_king<BLACK, HasPopCnt>(pos, ei);
-
- // Evaluate tactical threats, we need full attack info
- evaluate_threats<WHITE>(pos, ei);
- evaluate_threats<BLACK>(pos, ei);
-
- // Evaluate passed pawns. We evaluate passed pawns for both sides at once,
- // because we need to know which side promotes first in positions where
- // both sides have an unstoppable passed pawn. To be called after all attacks
- // are computed, included king.
- if (ei.pi->passed_pawns())
- evaluate_passed_pawns(pos, ei);
-
- Phase phase = pos.game_phase();
-
- // Middle-game specific evaluation terms
- if (phase > PHASE_ENDGAME)
- {
- // Pawn storms in positions with opposite castling.
- if ( square_file(pos.king_square(WHITE)) >= FILE_E
- && square_file(pos.king_square(BLACK)) <= FILE_D)
-
- ei.value += Score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0);
-
- else if ( square_file(pos.king_square(WHITE)) <= FILE_D
- && square_file(pos.king_square(BLACK)) >= FILE_E)
-
- ei.value += Score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0);
-
- // Evaluate space for both sides
- if (ei.mi->space_weight() > 0)
- {
- evaluate_space<WHITE, HasPopCnt>(pos, ei);
- evaluate_space<BLACK, HasPopCnt>(pos, ei);
- }
- }
-
- // Mobility
- ei.value += apply_weight(Score(ei.mgMobility, ei.egMobility), WeightMobilityMidgame, WeightMobilityEndgame);
-
- // If we don't already have an unusual scale factor, check for opposite
- // colored bishop endgames, and use a lower scale for those
- if ( phase < PHASE_MIDGAME
- && pos.opposite_colored_bishops()
- && ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.value.eg() > Value(0))
- || (factor[BLACK] == SCALE_FACTOR_NORMAL && ei.value.eg() < Value(0))))
- {
- ScaleFactor sf;
-
- // Only the two bishops ?
- if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
- && pos.non_pawn_material(BLACK) == BishopValueMidgame)
- {
- // Check for KBP vs KB with only a single pawn that is almost
- // certainly a draw or at least two pawns.
- bool one_pawn = (pos.piece_count(WHITE, PAWN) + pos.piece_count(BLACK, PAWN) == 1);
- sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
- }
- else
- // Endgame with opposite-colored bishops, but also other pieces. Still
- // a bit drawish, but not as drawish as with only the two bishops.
- sf = ScaleFactor(50);
-
- if (factor[WHITE] == SCALE_FACTOR_NORMAL)
- factor[WHITE] = sf;
- if (factor[BLACK] == SCALE_FACTOR_NORMAL)
- factor[BLACK] = sf;