// Evaluation weights, initialized from UCI options
enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
- Score Weights[6];
+ struct Weight { int mg, eg; } Weights[6];
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
{ S(-17,-33), S(-11,-16), S(-5, 0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks
S( 18, 64), S( 22, 80), S(26, 96), S(29,109), S(31,115), S(33,119),
S( 35,122), S( 36,123), S(37,124) },
- { S(-12,-20), S( -8,-13), S(-5, -7), S(-2, -1), S( 1, 5), S( 4, 11), // Queens
- S( 7, 17), S( 10, 23), S(13, 29), S(16, 34), S(18, 38), S(20, 40),
+ { S(-12,-20), S( -8,-13), S(-5, -7), S( 0, 0), S( 6, 10), S(11, 19), // Queens
+ S( 13, 29), S( 18, 38), S(20, 40), S(21, 41), S(22, 41), S(22, 41),
S( 22, 41), S( 23, 41), S(24, 41), S(25, 41), S(25, 41), S(25, 41),
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41) }
const Score Tempo = make_score(24, 11);
const Score RookOn7th = make_score(11, 20);
- const Score QueenOn7th = make_score( 3, 8);
const Score RookOnPawn = make_score(10, 28);
- const Score QueenOnPawn = make_score( 4, 20);
const Score RookOpenFile = make_score(43, 21);
const Score RookSemiopenFile = make_score(19, 10);
const Score BishopPawns = make_score( 8, 12);
const Score UndefendedMinor = make_score(25, 10);
const Score TrappedRook = make_score(90, 0);
const Score Unstoppable = make_score( 0, 20);
+ const Score LowMobPenalty = make_score(40, 20);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
(FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB)
};
+ const Bitboard EdgeBB = Rank1BB | Rank8BB | FileABB | FileHBB;
+
// King danger constants and variables. The king danger scores are taken
// from KingDanger[]. Various little "meta-bonuses" measuring the strength
// of the enemy attack are added up into an integer, which is used as an
template<Color Us>
void init_eval_info(const Position& pos, EvalInfo& ei);
- template<Color Us, bool Trace>
- Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility);
+ 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);
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, Score w);
- Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
+ Score apply_weight(Score v, const Weight& w);
+ Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
}
init_eval_info<WHITE>(pos, ei);
init_eval_info<BLACK>(pos, ei);
- // Evaluate pieces and mobility
- score += evaluate_pieces<WHITE, Trace>(pos, ei, mobility)
- - evaluate_pieces<BLACK, Trace>(pos, ei, mobility);
+ 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
Tracing::add_term(Tracing::PST, pos.psq_score());
Tracing::add_term(Tracing::IMBALANCE, ei.mi->material_value());
Tracing::add_term(PAWN, ei.pi->pawns_value());
+ Tracing::add_term(Tracing::MOBILITY, apply_weight(mobility[WHITE], Weights[Mobility])
+ , apply_weight(mobility[BLACK], Weights[Mobility]));
Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
Tracing::add_term(Tracing::SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
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);
+ ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
// Init king safety tables only if we are going to use them
if (pos.count<QUEEN>(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
// evaluate_pieces() assigns bonuses and penalties to the pieces of a given color
template<PieceType Pt, Color Us, bool Trace>
- Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard mobilityArea) {
+ Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea) {
Bitboard b;
Square s;
if (ei.pinnedPieces[Us] & s)
b &= LineBB[pos.king_square(Us)][s];
- ei.attackedBy[Us][Pt] |= b;
+ ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b;
if (b & ei.kingRing[Them])
{
ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
}
- int mob = Pt != QUEEN ? popcount<Max15>(b & mobilityArea)
- : popcount<Full >(b & mobilityArea);
+ if (Pt == QUEEN)
+ b &= ~( ei.attackedBy[Them][KNIGHT]
+ | ei.attackedBy[Them][BISHOP]
+ | ei.attackedBy[Them][ROOK]);
+
+ int mob = Pt != QUEEN ? popcount<Max15>(b & mobilityArea[Us])
+ : popcount<Full >(b & mobilityArea[Us]);
mobility[Us] += MobilityBonus[Pt][mob];
+ if (mob <= 1 && (EdgeBB & s))
+ score -= LowMobPenalty;
+
// 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 += MinorBehindPawn;
}
- if ( (Pt == ROOK || Pt == QUEEN)
- && relative_rank(Us, s) >= RANK_5)
+ if (Pt == ROOK)
{
- // Major piece on 7th rank and enemy king trapped on 8th
+ // Rook on 7th rank and enemy king trapped on 8th
if ( relative_rank(Us, s) == RANK_7
&& relative_rank(Us, pos.king_square(Them)) == RANK_8)
- score += Pt == ROOK ? RookOn7th : QueenOn7th;
+ score += RookOn7th;
- // Major piece attacking enemy pawns on the same rank/file
- Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
- if (pawns)
- score += popcount<Max15>(pawns) * (Pt == ROOK ? RookOnPawn : QueenOnPawn);
- }
+ // Rook piece attacking enemy pawns on the same rank/file
+ if (relative_rank(Us, s) >= RANK_5)
+ {
+ Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
+ if (pawns)
+ score += popcount<Max15>(pawns) * RookOnPawn;
+ }
- // Special extra evaluation for rooks
- if (Pt == ROOK)
- {
// Give a bonus for a rook on a open or semi-open file
if (ei.pi->semiopen(Us, file_of(s)))
score += ei.pi->semiopen(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
if (Trace)
Tracing::terms[Us][Pt] = score;
- return score;
- }
-
-
- // evaluate_pieces() assigns bonuses and penalties to all the
- // pieces of a given color.
-
- template<Color Us, bool Trace>
- Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility) {
-
- const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1));
- // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
- const Bitboard mobilityArea = ~(ei.attackedBy[Them][PAWN] | pos.pieces(Us, PAWN, KING));
-
- Score score = evaluate_pieces<KNIGHT, Us, Trace>(pos, ei, mobility, mobilityArea)
- + evaluate_pieces<BISHOP, Us, Trace>(pos, ei, mobility, mobilityArea)
- + evaluate_pieces<ROOK, Us, Trace>(pos, ei, mobility, mobilityArea)
- + evaluate_pieces<QUEEN, Us, Trace>(pos, ei, mobility, mobilityArea);
-
- // Sum up all attacked squares (updated in evaluate_pieces)
- ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT]
- | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
- | ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING];
- if (Trace)
- Tracing::terms[Us][Tracing::MOBILITY] = apply_weight(mobility[Us], Weights[Mobility]);
-
- return score;
+ return score - evaluate_pieces<NextPt, Them, Trace>(pos, ei, mobility, mobilityArea);
}
+ template<>
+ Score evaluate_pieces<KING, WHITE, false>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+ template<>
+ Score evaluate_pieces<KING, WHITE, true>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+
// evaluate_king() assigns bonuses and penalties to a king of a given color
// the pawn shelter (current 'score' value).
attackUnits = std::min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
+ + 2 * (ei.pinnedPieces[Us] != 0)
- mg_value(score) / 32;
// Analyse the enemy's safe queen contact checks. Firstly, find the
}
// apply_weight() weights score v by score w trying to prevent overflow
- Score apply_weight(Score v, Score w) {
+ Score apply_weight(Score v, const Weight& w) {
- return make_score((int(mg_value(v)) * mg_value(w)) / 0x100,
- (int(eg_value(v)) * eg_value(w)) / 0x100);
+ return make_score(mg_value(v) * w.mg / 256, eg_value(v) * w.eg / 256);
}
// weight_option() computes the value of an evaluation weight, by combining
// two UCI-configurable weights (midgame and endgame) with an internal weight.
- Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
-
- // Scale option value from 100 to 256
- int mg = Options[mgOpt] * 256 / 100;
- int eg = Options[egOpt] * 256 / 100;
+ Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
- return apply_weight(make_score(mg, eg), internalWeight);
+ Weight w = { Options[mgOpt] * mg_value(internalWeight) / 100,
+ Options[egOpt] * eg_value(internalWeight) / 100 };
+ return w;
}
// Tracing function definitions
- double Tracing::to_cp(Value v) { return double(v) / PawnValueMg; }
+ double Tracing::to_cp(Value v) { return double(v) / PawnValueEg; }
void Tracing::add_term(int idx, Score wScore, Score bScore) {
switch (idx) {
case PST: case IMBALANCE: case PAWN: case TOTAL:
ss << std::setw(20) << name << " | --- --- | --- --- | "
- << std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
- << std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n";
+ << std::setw(5) << to_cp(mg_value(wScore - bScore)) << " "
+ << std::setw(5) << to_cp(eg_value(wScore - bScore)) << " \n";
break;
default:
ss << std::setw(20) << name << " | " << std::noshowpos
<< std::setw(5) << to_cp(eg_value(wScore)) << " | "
<< std::setw(5) << to_cp(mg_value(bScore)) << " "
<< std::setw(5) << to_cp(eg_value(bScore)) << " | "
- << std::showpos
- << std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
- << std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n";
+ << std::setw(5) << to_cp(mg_value(wScore - bScore)) << " "
+ << std::setw(5) << to_cp(eg_value(wScore - bScore)) << " \n";
}
}
std::memset(terms, 0, sizeof(terms));
Value v = do_evaluate<true>(pos);
+ v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
std::stringstream ss;
- ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2)
- << " Eval term | White | Black | Total \n"
- << " | MG EG | MG EG | MG EG \n"
- << "---------------------+-------------+-------------+---------------\n";
+ ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
+ << " Eval term | White | Black | Total \n"
+ << " | MG EG | MG EG | MG EG \n"
+ << "---------------------+-------------+-------------+-------------\n";
format_row(ss, "Material, PST, Tempo", PST);
format_row(ss, "Material imbalance", IMBALANCE);
format_row(ss, "Passed pawns", PASSED);
format_row(ss, "Space", SPACE);
- ss << "---------------------+-------------+-------------+---------------\n";
+ ss << "---------------------+-------------+-------------+-------------\n";
format_row(ss, "Total", TOTAL);
- ss << "\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"
- << "Total evaluation: " << to_cp(v);
+ ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n";
return ss.str();
}