X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=3228c9a129df5e84903d2984e7e581a24482f07c;hp=8c84ac299777e7ff7a33f91cb2f9e439de783686;hb=0510112f9184db3be86492267a4564035f954ec6;hpb=af0c13ba6ad5d51432a8f4531d53c7309484df6b diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8c84ac29..3228c9a1 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -91,7 +91,7 @@ namespace { // 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) @@ -111,16 +111,16 @@ namespace { // friendly pieces. const Score MobilityBonus[][32] = { {}, {}, - { S(-35,-30), S(-22,-20), S(-9,-10), S( 3, 0), S(15, 10), S(27, 20), // Knights + { S(-65,-50), S(-42,-30), S(-9,-10), S( 3, 0), S(15, 10), S(27, 20), // Knights S( 37, 28), S( 42, 31), S(44, 33) }, - { S(-22,-27), S( -8,-13), S( 6, 1), S(20, 15), S(34, 29), S(48, 43), // Bishops + { S(-52,-47), S(-28,-23), S( 6, 1), S(20, 15), S(34, 29), S(48, 43), // Bishops S( 60, 55), S( 68, 63), S(74, 68), S(77, 72), S(80, 75), S(82, 77), S( 84, 79), S( 86, 81) }, - { S(-17,-33), S(-11,-16), S(-5, 0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks + { S(-47,-53), S(-31,-26), 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(-42,-40), S(-28,-23), 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) } @@ -162,9 +162,7 @@ namespace { 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); @@ -204,8 +202,6 @@ namespace { const int BishopCheck = 2; const int KnightCheck = 3; - const int UnsupportedPinnedPiece = 2; - // KingDanger[Color][attackUnits] contains the actual king danger weighted // scores, indexed by color and by a calculated integer number. Score KingDanger[COLOR_NB][128]; @@ -217,8 +213,8 @@ namespace { template void init_eval_info(const Position& pos, EvalInfo& ei); - template - Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility); + template + Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea); template Score evaluate_king(const Position& pos, const EvalInfo& ei); @@ -235,8 +231,8 @@ namespace { 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); } @@ -320,10 +316,15 @@ Value do_evaluate(const Position& pos) { init_eval_info(pos, ei); init_eval_info(pos, ei); - // Evaluate pieces and mobility - score += evaluate_pieces(pos, ei, mobility) - - evaluate_pieces(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(pos, ei, mobility, mobilityArea); score += apply_weight(mobility[WHITE] - mobility[BLACK], Weights[Mobility]); // Evaluate kings after all other pieces because we need complete attack @@ -385,6 +386,8 @@ Value do_evaluate(const Position& pos) { 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(pos, ei); Score b = ei.mi->space_weight() * evaluate_space(pos, ei); Tracing::add_term(Tracing::SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space])); @@ -409,7 +412,7 @@ Value do_evaluate(const Position& pos) { ei.pinnedPieces[Us] = pos.pinned_pieces(Us); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(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(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg) @@ -454,7 +457,7 @@ Value do_evaluate(const Position& pos) { // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color template - 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; @@ -475,7 +478,7 @@ Value do_evaluate(const Position& pos) { 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]) { @@ -486,8 +489,13 @@ Value do_evaluate(const Position& pos) { ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb); } - int mob = Pt != QUEEN ? popcount(b & mobilityArea) - : popcount(b & mobilityArea); + if (Pt == QUEEN) + b &= ~( ei.attackedBy[Them][KNIGHT] + | ei.attackedBy[Them][BISHOP] + | ei.attackedBy[Them][ROOK]); + + int mob = Pt != QUEEN ? popcount(b & mobilityArea[Us]) + : popcount(b & mobilityArea[Us]); mobility[Us] += MobilityBonus[Pt][mob]; @@ -516,23 +524,21 @@ Value do_evaluate(const Position& pos) { 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(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(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; @@ -568,36 +574,16 @@ Value do_evaluate(const Position& pos) { if (Trace) Tracing::terms[Us][Pt] = score; - return score; - } + const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1)); - - // evaluate_pieces() assigns bonuses and penalties to all the - // pieces of a given color. - - template - Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility) { - - const Color Them = (Us == WHITE ? BLACK : WHITE); - - // 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(pos, ei, mobility, mobilityArea) - + evaluate_pieces(pos, ei, mobility, mobilityArea) - + evaluate_pieces(pos, ei, mobility, mobilityArea) - + evaluate_pieces(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(pos, ei, mobility, mobilityArea); } + template<> + Score evaluate_pieces(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; } + template<> + Score evaluate_pieces(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; } + // evaluate_king() assigns bonuses and penalties to a king of a given color @@ -631,6 +617,7 @@ Value do_evaluate(const Position& pos) { // the pawn shelter (current 'score' value). attackUnits = std::min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount(undefended)) + + 2 * (ei.pinnedPieces[Us] != 0) - mg_value(score) / 32; // Analyse the enemy's safe queen contact checks. Firstly, find the @@ -695,10 +682,6 @@ Value do_evaluate(const Position& pos) { if (b) attackUnits += KnightCheck * popcount(b); - // Penalty for pinned pieces not defended by a pawn - if (ei.pinnedPieces[Us] & ~ei.attackedBy[Us][PAWN]) - attackUnits += UnsupportedPinnedPiece; - // To index KingDanger[] attackUnits must be in [0, 99] range attackUnits = std::min(99, std::max(0, attackUnits)); @@ -930,28 +913,25 @@ Value do_evaluate(const Position& pos) { } // 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) { @@ -967,8 +947,8 @@ Value do_evaluate(const Position& pos) { 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 @@ -976,9 +956,8 @@ Value do_evaluate(const Position& pos) { << 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"; } } @@ -987,12 +966,13 @@ Value do_evaluate(const Position& pos) { std::memset(terms, 0, sizeof(terms)); Value v = do_evaluate(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); @@ -1007,14 +987,10 @@ Value do_evaluate(const Position& pos) { 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(); }