X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fevaluate.cpp;h=a945c5c7f2c29d34b18ac2ccd08ac3c6b97dcc9d;hb=40f5abba104b411ec5234e2c93b05bba8e6bd3c8;hp=8eb0364844a363e5fb33e5a7e55a4d8e26dd739c;hpb=a4d058bca25b65c52b0be063d4c5d2ca50d6a25c;p=stockfish diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8eb03648..a945c5c7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -17,10 +17,10 @@ along with this program. If not, see . */ +#include #include #include #include -#include #include "bitcount.h" #include "evaluate.h" @@ -90,8 +90,8 @@ namespace { } // Evaluation weights, initialized from UCI options - enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem }; - struct Weight { int mg, eg; } Weights[6]; + enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety }; + struct Weight { int mg, eg; } Weights[5]; typedef Value V; #define S(mg, eg) make_score(mg, eg) @@ -103,7 +103,7 @@ namespace { // // Values modified by Joona Kiiski const Score WeightsInternal[] = { - S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0) + S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(289, 0) }; // MobilityBonus[PieceType][attacked] contains bonuses for middle and end @@ -158,17 +158,17 @@ namespace { S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118) }; + // Hanging[side to move] contains a bonus for each enemy hanging piece + const Score Hanging[2] = { S(23, 20) , S(35, 45) }; + #undef S const Score Tempo = make_score(24, 11); - const Score RookOn7th = make_score(11, 20); const Score RookOnPawn = make_score(10, 28); const Score RookOpenFile = make_score(43, 21); const Score RookSemiopenFile = make_score(19, 10); const Score BishopPawns = make_score( 8, 12); - const Score KnightPawns = make_score( 8, 4); const Score MinorBehindPawn = make_score(16, 0); - const Score UndefendedMinor = make_score(25, 10); const Score TrappedRook = make_score(90, 0); const Score Unstoppable = make_score( 0, 20); @@ -202,9 +202,9 @@ namespace { const int BishopCheck = 2; const int KnightCheck = 3; - // KingDanger[Color][attackUnits] contains the actual king danger weighted - // scores, indexed by color and by a calculated integer number. - Score KingDanger[COLOR_NB][128]; + // KingDanger[attackUnits] contains the actual king danger weighted + // scores, indexed by a calculated integer number. + Score KingDanger[128]; // apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow @@ -224,20 +224,6 @@ namespace { } - // interpolate() interpolates between a middlegame and an endgame score, - // based on game phase. It also scales the return value by a ScaleFactor array. - - Value interpolate(const Score& v, Phase ph, ScaleFactor sf) { - - assert(-VALUE_INFINITE < mg_value(v) && mg_value(v) < VALUE_INFINITE); - assert(-VALUE_INFINITE < eg_value(v) && eg_value(v) < VALUE_INFINITE); - assert(PHASE_ENDGAME <= ph && ph <= PHASE_MIDGAME); - - int eg = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL; - return Value((mg_value(v) * int(ph) + eg * int(PHASE_MIDGAME - ph)) / PHASE_MIDGAME); - } - - // init_eval_info() initializes king bitboards for given color adding // pawn attacks. To be done at the beginning of the evaluation. @@ -349,10 +335,6 @@ namespace { if (Pt == BISHOP) score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s); - // Penalty for knight when there are few enemy pawns - if (Pt == KNIGHT) - score -= KnightPawns * std::max(5 - pos.count(Them), 0); - // Bishop and knight outposts squares if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s))) score += evaluate_outposts(pos, ei, s); @@ -365,11 +347,6 @@ namespace { if (Pt == ROOK) { - // 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 += RookOn7th; - // Rook piece attacking enemy pawns on the same rank/file if (relative_rank(Us, s) >= RANK_5) { @@ -524,7 +501,7 @@ namespace { // Finally, extract the king danger score from the KingDanger[] // array and subtract the score from evaluation. - score -= KingDanger[Us == Search::RootColor][attackUnits]; + score -= KingDanger[attackUnits]; } if (Trace) @@ -542,17 +519,10 @@ namespace { const Color Them = (Us == WHITE ? BLACK : WHITE); - Bitboard b, undefendedMinors, weakEnemies; + Bitboard b, weakEnemies; Score score = SCORE_ZERO; - // Undefended minors get penalized even if they are not under attack - undefendedMinors = pos.pieces(Them, BISHOP, KNIGHT) - & ~ei.attackedBy[Them][ALL_PIECES]; - - if (undefendedMinors) - score += UndefendedMinor; - - // Enemy pieces not defended by a pawn and under our attack + // Enemies not defended by a pawn and under our attack weakEnemies = pos.pieces(Them) & ~ei.attackedBy[Them][PAWN] & ei.attackedBy[Us][ALL_PIECES]; @@ -560,13 +530,18 @@ namespace { // Add a bonus according if the attacking pieces are minor or major if (weakEnemies) { - b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]); + b = weakEnemies & (ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]); if (b) score += Threat[0][type_of(pos.piece_on(lsb(b)))]; b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]); if (b) score += Threat[1][type_of(pos.piece_on(lsb(b)))]; + + b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES]; + if (b) + score += more_than_one(b) ? Hanging[Us != pos.side_to_move()] * popcount(b) + : Hanging[Us == pos.side_to_move()]; } if (Trace) @@ -594,24 +569,23 @@ namespace { assert(pos.pawn_passed(Us, s)); - int r = int(relative_rank(Us, s) - RANK_2); + int r = relative_rank(Us, s) - RANK_2; int rr = r * (r - 1); // Base bonus based on rank - Value mbonus = Value(17 * rr); - Value ebonus = Value(7 * (rr + r + 1)); + Value mbonus = Value(17 * rr), ebonus = Value(7 * (rr + r + 1)); if (rr) { Square blockSq = s + pawn_push(Us); // Adjust bonus based on the king's proximity - ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 5 * rr) - - Value(square_distance(pos.king_square(Us ), blockSq) * 2 * rr); + ebonus += square_distance(pos.king_square(Them), blockSq) * 5 * rr + - square_distance(pos.king_square(Us ), blockSq) * 2 * rr; // If blockSq is not the queening square then consider also a second push if (relative_rank(Us, blockSq) != RANK_8) - ebonus -= Value(rr * square_distance(pos.king_square(Us), blockSq + pawn_push(Us))); + ebonus -= square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr; // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) @@ -645,25 +619,10 @@ namespace { else if (defendedSquares & blockSq) k += 4; - mbonus += Value(k * rr), ebonus += Value(k * rr); + mbonus += k * rr, ebonus += k * rr; } } // rr != 0 - // Rook pawns are a special case: They are sometimes worse, and - // sometimes better than other passed pawns. It is difficult to find - // good rules for determining whether they are good or bad. For now, - // we try the following: Increase the value for rook pawns if the - // other side has no pieces apart from a knight, and decrease the - // value if the other side has a rook or queen. - if (file_of(s) == FILE_A || file_of(s) == FILE_H) - { - if (pos.non_pawn_material(Them) <= KnightValueMg) - ebonus += ebonus / 4; - - else if (pos.pieces(Them, ROOK, QUEEN)) - ebonus -= ebonus / 4; - } - if (pos.count(Us) < pos.count(Them)) ebonus += ebonus / 4; @@ -761,7 +720,7 @@ namespace { 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 + // Do not include in mobility squares protected by enemy pawns or occupied by our pawns or king Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | pos.pieces(WHITE, PAWN, KING)), ~(ei.attackedBy[WHITE][PAWN] | pos.pieces(BLACK, PAWN, KING)) }; @@ -820,7 +779,11 @@ namespace { sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL); } - Value v = interpolate(score, ei.mi->game_phase(), sf); + // Interpolate between a middlegame and a (scaled by 'sf') endgame score + Value v = mg_value(score) * int(ei.mi->game_phase()) + + eg_value(score) * int(PHASE_MIDGAME - ei.mi->game_phase()) * sf / SCALE_FACTOR_NORMAL; + + v /= int(PHASE_MIDGAME); // In case of tracing add all single evaluation contributions for both white and black if (Trace) @@ -939,18 +902,15 @@ namespace Eval { 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]); + Weights[KingSafety] = weight_option("King Safety", "King Safety", WeightsInternal[KingSafety]); - const int MaxSlope = 30; - const int Peak = 1280; + const double MaxSlope = 30; + const double 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]); + t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope))); + KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]); } }