X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=4667d51531205f67bd77f255c56ca8c7a9c3818f;hp=48c6e8ea1d7befaee0235485fcd07a4a28b5c412;hb=b5581b7779b6e286fa2277625572996477d74b10;hpb=ed26d71354c3ab1a1419975430258b6e961787a7 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 48c6e8ea..4667d515 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -28,8 +28,7 @@ #include "evaluate.h" #include "material.h" #include "pawns.h" - -std::atomic Eval::Contempt; +#include "thread.h" namespace Trace { @@ -80,9 +79,9 @@ namespace { constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); constexpr Bitboard KingFlank[FILE_NB] = { - QueenSide, QueenSide, QueenSide, + QueenSide ^ FileDBB, QueenSide, QueenSide, CenterFiles, CenterFiles, - KingSide, KingSide, KingSide + KingSide, KingSide, KingSide ^ FileEBB }; // Threshold for lazy and space evaluation @@ -90,7 +89,7 @@ namespace { constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 }; + constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10 }; // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; @@ -141,46 +140,41 @@ namespace { S(0, 0), S(0, 24), S(38, 71), S(38, 61), S(0, 38), S(36, 38) }; - // ThreatByKing[on one/on many] contains bonuses for king attacks on - // pawns or pieces which are not pawn-defended. - constexpr Score ThreatByKing[] = { S(3, 65), S(9, 145) }; - // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(5, 7), S(5, 13), S(32, 42), S(70, 70), S(172, 170), S(217, 269) + S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250) }; // PassedFile[File] contains a bonus according to the file of a passed pawn constexpr Score PassedFile[FILE_NB] = { - S( 9, 10), S(2, 10), S(1, -8), S(-20,-12), - S(-20,-12), S(1, -8), S(2, 10), S( 9, 10) + S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14), + S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7) }; // PassedDanger[Rank] contains a term to weight the passed score - constexpr int PassedDanger[RANK_NB] = { 0, 0, 0, 2, 7, 12, 19 }; - - // KingProtector[PieceType-2] contains a penalty according to distance from king - constexpr Score KingProtector[] = { S(3, 5), S(4, 3), S(3, 0), S(1, -1) }; + constexpr int PassedDanger[RANK_NB] = { 0, 0, 0, 3, 7, 11, 20 }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 8, 12); - constexpr Score CloseEnemies = S( 7, 0); - constexpr Score Connectivity = S( 3, 1); + constexpr Score BishopPawns = S( 3, 7); + constexpr Score CloseEnemies = S( 6, 0); constexpr Score CorneredBishop = S( 50, 50); - constexpr Score Hanging = S( 52, 30); - constexpr Score HinderPassedPawn = S( 8, 1); + constexpr Score Hanging = S( 57, 32); + constexpr Score HinderPassedPawn = S( 8, 0); + constexpr Score KingProtector = S( 6, 6); constexpr Score KnightOnQueen = S( 21, 11); constexpr Score LongDiagonalBishop = S( 22, 0); constexpr Score MinorBehindPawn = S( 16, 0); - constexpr Score PawnlessFlank = S( 20, 80); - constexpr Score RookOnPawn = S( 8, 24); + constexpr Score Overload = S( 13, 6); + constexpr Score PawnlessFlank = S( 19, 84); + constexpr Score RookOnPawn = S( 10, 30); constexpr Score SliderOnQueen = S( 42, 21); - constexpr Score ThreatByPawnPush = S( 47, 26); + constexpr Score ThreatByKing = S( 23, 76); + constexpr Score ThreatByPawnPush = S( 45, 40); constexpr Score ThreatByRank = S( 16, 3); - constexpr Score ThreatBySafePawn = S(175,168); + constexpr Score ThreatBySafePawn = S(173,102); constexpr Score TrappedRook = S( 92, 0); constexpr Score WeakQueen = S( 50, 10); - constexpr Score WeakUnopposedPawn = S( 5, 25); + constexpr Score WeakUnopposedPawn = S( 5, 29); #undef S @@ -258,9 +252,9 @@ namespace { // Find our pawns that are blocked or on the first two ranks Bitboard b = pos.pieces(Us, PAWN) & (shift(pos.pieces()) | LowRanks); - // Squares occupied by those pawns, by our king, or controlled by enemy pawns + // Squares occupied by those pawns, by our king or queen, or controlled by enemy pawns // are excluded from the mobility area. - mobilityArea[Us] = ~(b | pos.square(Us) | pe->pawn_attacks(Them)); + mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); // Initialise attackedBy bitboards for kings and pawns attackedBy[Us][KING] = pos.attacks_from(pos.square(Us)); @@ -275,7 +269,13 @@ namespace { if (relative_rank(Us, pos.square(Us)) == RANK_1) kingRing[Us] |= shift(kingRing[Us]); - kingAttackersCount[Them] = popcount(attackedBy[Us][KING] & pe->pawn_attacks(Them)); + if (file_of(pos.square(Us)) == FILE_H) + kingRing[Us] |= shift(kingRing[Us]); + + else if (file_of(pos.square(Us)) == FILE_A) + kingRing[Us] |= shift(kingRing[Us]); + + kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; } else @@ -287,7 +287,8 @@ namespace { template template Score Evaluation::pieces() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); const Square* pl = pos.squares(Us); @@ -323,9 +324,6 @@ namespace { mobility[Us] += MobilityBonus[Pt - 2][mob]; - // Penalty if the piece is far from the king - score -= KingProtector[Pt - 2] * distance(s, pos.square(Us)); - if (Pt == BISHOP || Pt == KNIGHT) { // Bonus if piece is on an outpost square or can reach one @@ -336,15 +334,21 @@ namespace { else if (bb &= b & ~pos.pieces(Us)) score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)]; - // Bonus when behind a pawn - if ( relative_rank(Us, s) < RANK_5 - && (pos.pieces(PAWN) & (s + pawn_push(Us)))) + // Knight and Bishop bonus for being right behind a pawn + if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; + // Penalty if the piece is far from the king + score -= KingProtector * distance(s, pos.square(Us)); + if (Pt == BISHOP) { - // Penalty according to number of pawns on the same color square as the bishop - score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s); + // Penalty according to number of pawns on the same color square as the + // bishop, bigger when the center files are blocked with pawns. + Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); + + score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s) + * (1 + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(Center & (attacks_bb(s, pos.pieces(PAWN)) | s))) @@ -368,7 +372,7 @@ namespace { if (Pt == ROOK) { - // Bonus for aligning rook with with enemy pawns on the same rank/file + // Bonus for aligning rook with enemy pawns on the same rank/file if (relative_rank(Us, s) >= RANK_5) score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); @@ -406,14 +410,22 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB - : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); + : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); const Square ksq = pos.square(Us); - Bitboard weak, b, b1, b2, safe, unsafeChecks, pinned; + Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks; // King shelter and enemy pawns storm Score score = pe->king_safety(pos, ksq); + // Find the squares that opponent attacks in our king flank, and the squares + // which are attacked twice in that flank but not defended by our pawns. + kingFlank = KingFlank[file_of(ksq)]; + b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; + b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN]; + + int tropism = popcount(b1) + popcount(b2); + // Main king safety evaluation if (kingAttackersCount[Them] > 1 - pos.count(Them)) { @@ -461,15 +473,15 @@ namespace { // Unsafe or occupied checking squares will also be considered, as long as // the square is in the attacker's mobility area. unsafeChecks &= mobilityArea[Them]; - pinned = pos.blockers_for_king(Us) & pos.pieces(Us); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 102 * kingAttacksCount[Them] - + 191 * popcount(kingRing[Us] & weak) - + 143 * popcount(pinned | unsafeChecks) - - 848 * !pos.count(Them) - - 9 * mg_value(score) / 8 - + 40; + + 69 * kingAttacksCount[Them] + + 185 * popcount(kingRing[Us] & weak) + + 129 * popcount(pos.blockers_for_king(Us) | unsafeChecks) + + 4 * tropism + - 873 * !pos.count(Them) + - 6 * mg_value(score) / 8 + - 30; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 0) @@ -480,19 +492,12 @@ namespace { } } - Bitboard kf = KingFlank[file_of(ksq)]; - // Penalty when our king is on a pawnless flank - if (!(pos.pieces(PAWN) & kf)) + if (!(pos.pieces(PAWN) & kingFlank)) score -= PawnlessFlank; - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank but not defended by our pawns. - b1 = attackedBy[Them][ALL_PIECES] & kf & Camp; - b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN]; - - // King tropism, to anticipate slow motion attacks on our king - score -= CloseEnemies * (popcount(b1) + popcount(b2)); + // King tropism bonus, to anticipate slow motion attacks on our king + score -= CloseEnemies * tropism; if (T) Trace::add(KING, Us, score); @@ -510,22 +515,11 @@ namespace { constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safeThreats; + Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; Score score = SCORE_ZERO; - // Non-pawn enemies attacked by a pawn + // Non-pawn enemies nonPawnEnemies = pos.pieces(Them) ^ pos.pieces(Them, PAWN); - weak = nonPawnEnemies & attackedBy[Us][PAWN]; - - if (weak) - { - // Our safe or protected pawns - b = pos.pieces(Us, PAWN) - & (~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]); - - safeThreats = pawn_attacks_bb(b) & weak; - score += ThreatBySafePawn * popcount(safeThreats); - } // Squares strongly protected by the enemy, either because they defend the // square with a pawn, or because they defend the square twice and we don't. @@ -538,6 +532,9 @@ namespace { // Enemies not strongly protected and under our attack weak = pos.pieces(Them) & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; + // Safe or protected squares + safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; + // Bonus according to the kind of attacking pieces if (defended | weak) { @@ -548,22 +545,30 @@ namespace { score += ThreatByMinor[type_of(pos.piece_on(s))]; if (type_of(pos.piece_on(s)) != PAWN) score += ThreatByRank * (int)relative_rank(Them, s); + + else if (pos.blockers_for_king(Them) & s) + score += ThreatByRank * (int)relative_rank(Them, s) / 2; } - b = (pos.pieces(Them, QUEEN) | weak) & attackedBy[Us][ROOK]; + b = weak & attackedBy[Us][ROOK]; while (b) { Square s = pop_lsb(&b); score += ThreatByRook[type_of(pos.piece_on(s))]; if (type_of(pos.piece_on(s)) != PAWN) score += ThreatByRank * (int)relative_rank(Them, s); + + else if (pos.blockers_for_king(Them) & s) + score += ThreatByRank * (int)relative_rank(Them, s) / 2; } + if (weak & attackedBy[Us][KING]) + score += ThreatByKing; + score += Hanging * popcount(weak & ~attackedBy[Them][ALL_PIECES]); - b = weak & attackedBy[Us][KING]; - if (b) - score += ThreatByKing[more_than_one(b)]; + b = weak & nonPawnEnemies & attackedBy[Them][ALL_PIECES]; + score += Overload * popcount(b); } // Bonus for enemy unopposed weak pawns @@ -574,37 +579,35 @@ namespace { b = shift(pos.pieces(Us, PAWN)) & ~pos.pieces(); b |= shift(b & TRank3BB) & ~pos.pieces(); - // Keep only the squares which are not completely unsafe - b &= ~attackedBy[Them][PAWN] - & (attackedBy[Us][ALL_PIECES] | ~attackedBy[Them][ALL_PIECES]); + // Keep only the squares which are relatively safe + b &= ~attackedBy[Them][PAWN] & safe; // Bonus for safe pawn threats on the next move - b = pawn_attacks_bb(b) - & pos.pieces(Them) - & ~attackedBy[Us][PAWN]; - + b = pawn_attacks_bb(b) & pos.pieces(Them); score += ThreatByPawnPush * popcount(b); + // Our safe or protected pawns + b = pos.pieces(Us, PAWN) & safe; + + b = pawn_attacks_bb(b) & nonPawnEnemies; + score += ThreatBySafePawn * popcount(b); + // Bonus for threats on the next moves against enemy queen if (pos.count(Them) == 1) { Square s = pos.square(Them); - safeThreats = mobilityArea[Us] & ~stronglyProtected; + safe = mobilityArea[Us] & ~stronglyProtected; b = attackedBy[Us][KNIGHT] & pos.attacks_from(s); - score += KnightOnQueen * popcount(b & safeThreats); + score += KnightOnQueen * popcount(b & safe); b = (attackedBy[Us][BISHOP] & pos.attacks_from(s)) | (attackedBy[Us][ROOK ] & pos.attacks_from(s)); - score += SliderOnQueen * popcount(b & safeThreats & attackedBy2[Us]); + score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]); } - // Connectivity: ensure that knights, bishops, rooks, and queens are protected - b = (pos.pieces(Us) ^ pos.pieces(Us, PAWN, KING)) & attackedBy[Us][ALL_PIECES]; - score += Connectivity * popcount(b); - if (T) Trace::add(THREAT, Us, score); @@ -635,8 +638,8 @@ namespace { assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); - bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them)); - score -= HinderPassedPawn * popcount(bb); + if (forward_file_bb(Us, s) & pos.pieces(Them)) + score -= HinderPassedPawn; int r = relative_rank(Us, s); int w = PassedDanger[r]; @@ -687,10 +690,10 @@ namespace { } else if (pos.pieces(Us) & blockSq) bonus += make_score(w + r * 2, w + r * 2); - } // rr != 0 + } // w != 0 // Scale down bonus for candidate passers which need more than one - // pawn push to become passed or have a pawn in front of them. + // pawn push to become passed, or have a pawn in front of them. if ( !pos.pawn_passed(Us, s + Up) || (pos.pieces(PAWN) & forward_file_bb(Us, s))) bonus = bonus / 2; @@ -715,21 +718,18 @@ namespace { template template Score Evaluation::space() const { + if (pos.non_pawn_material() < SpaceThreshold) + return SCORE_ZERO; + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); - if (pos.non_pawn_material() < SpaceThreshold) - return SCORE_ZERO; - - // Find the safe squares for our pieces inside the area defined by - // SpaceMask. A square is unsafe if it is attacked by an enemy - // pawn, or if it is undefended and attacked by an enemy piece. + // Find the available squares for our pieces inside the area defined by SpaceMask Bitboard safe = SpaceMask & ~pos.pieces(Us, PAWN) - & ~attackedBy[Them][PAWN] - & (attackedBy[Us][ALL_PIECES] | ~attackedBy[Them][ALL_PIECES]); + & ~attackedBy[Them][PAWN]; // Find all squares which are at most three squares behind some friendly pawn Bitboard behind = pos.pieces(Us, PAWN); @@ -762,9 +762,9 @@ namespace { && (pos.pieces(PAWN) & KingSide); // Compute the initiative bonus for the attacking side - int complexity = 8 * outflanking - + 8 * pe->pawn_asymmetry() + int complexity = 8 * pe->pawn_asymmetry() + 12 * pos.count() + + 12 * outflanking + 16 * pawnsOnBothFlanks + 48 * !pos.non_pawn_material() -136 ; @@ -789,29 +789,15 @@ namespace { Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK; int sf = me->scale_factor(pos, strongSide); - // If we don't already have an unusual scale factor, check for certain - // types of endgames, and use a lower scale for those. - if (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN) + // If scale is not already specific, scale down the endgame via general heuristics + if (sf == SCALE_FACTOR_NORMAL) { - if (pos.opposite_bishops()) - { - // Endgame with opposite-colored bishops and no other pieces (ignoring pawns) - // is almost a draw, in case of KBP vs KB, it is even more a draw. - if ( pos.non_pawn_material(WHITE) == BishopValueMg - && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = more_than_one(pos.pieces(PAWN)) ? 31 : 9; - - // Endgame with opposite-colored bishops, but also other pieces. Still - // a bit drawish, but not as drawish as with only the two bishops. - else - sf = 46; - } - // Endings where weaker side can place his king in front of the enemy's - // pawns are drawish. - else if ( abs(eg) <= BishopValueEg - && pos.count(strongSide) <= 2 - && !pos.pawn_passed(~strongSide, pos.square(~strongSide))) - sf = 37 + 7 * pos.count(strongSide); + if ( pos.opposite_bishops() + && pos.non_pawn_material(WHITE) == BishopValueMg + && pos.non_pawn_material(BLACK) == BishopValueMg) + sf = 31; + else + sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); } return ScaleFactor(sf); @@ -838,7 +824,7 @@ namespace { // Initialize score by reading the incrementally updated scores included in // the position object (material + piece square tables) and the material // imbalance. Score is computed internally from the white point of view. - Score score = pos.psq_score() + me->imbalance() + Eval::Contempt; + Score score = pos.psq_score() + me->imbalance() + pos.this_thread()->contempt; // Probe the pawn hash table pe = Pawns::probe(pos); @@ -909,7 +895,7 @@ std::string Eval::trace(const Position& pos) { std::memset(scores, 0, sizeof(scores)); - Eval::Contempt = SCORE_ZERO; // Reset any dynamic contempt + pos.this_thread()->contempt = SCORE_ZERO; // Reset any dynamic contempt Value v = Evaluation(pos).value();