X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=2b7ab39678e7c461e224a0c0c7583af0812dfc41;hp=9a67a8e429024aa8f5453281c450aacbe322028d;hb=3468138210cacdf46051e9d5bde6e28effee2cdc;hpb=13ba67801f0331e3ffde23794b989765af5a9aa2 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9a67a8e4..2b7ab396 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -78,7 +78,7 @@ namespace { constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10 }; + constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; @@ -108,32 +108,30 @@ namespace { // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. - constexpr Score RookOnFile[] = { S(18, 7), S(44, 20) }; + constexpr Score RookOnFile[] = { S(21, 4), S(47, 25) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(0, 31), S(39, 42), S(57, 44), S(68, 112), S(62, 120) + S(0, 0), S(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(0, 24), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250) + S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; - // PassedFile[File] contains a bonus according to the file of a passed pawn - constexpr Score PassedFile[FILE_NB] = { - S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14), - S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7) + // OutpostRank[Rank] contains a bonus according to the rank of the outpost + constexpr Score OutpostRank[RANK_NB] = { + S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19) }; // Assorted bonuses and penalties - constexpr Score AttacksOnSpaceArea = S( 4, 0); constexpr Score BishopPawns = S( 3, 7); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@ -142,14 +140,14 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 18, 6); + constexpr Score Outpost = S( 32, 10); + constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnPawn = S( 10, 32); + constexpr Score RookOnQueenFile = S( 7, 6); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); - constexpr Score ThreatByRank = S( 13, 0); constexpr Score ThreatBySafePawn = S(173, 94); constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); @@ -174,7 +172,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Value eg) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@ -220,8 +218,8 @@ namespace { void Evaluation::initialize() { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); const Square ksq = pos.square(Us); @@ -242,15 +240,9 @@ namespace { attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); // Init our king safety tables - kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, ksq) == RANK_1) - kingRing[Us] |= shift(kingRing[Us]); - - if (file_of(ksq) == FILE_H) - kingRing[Us] |= shift(kingRing[Us]); - - else if (file_of(ksq) == FILE_A) - kingRing[Us] |= shift(kingRing[Us]); + Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G), + clamp(rank_of(ksq), RANK_2, RANK_7)); + kingRing[Us] = s | PseudoAttacks[KING][s]; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -265,7 +257,7 @@ namespace { Score Evaluation::pieces() { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); const Square* pl = pos.squares(Us); @@ -304,11 +296,11 @@ namespace { { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); - if (bb & s) - score += Outpost * (Pt == KNIGHT ? 4 : 2); + if (s & bb) + score += OutpostRank[relative_rank(Us, s)] * (Pt == KNIGHT ? 2 : 1); - else if (bb & b & ~pos.pieces(Us)) - score += Outpost * (Pt == KNIGHT ? 2 : 1); + else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) + score += Outpost; // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) @@ -348,13 +340,13 @@ namespace { if (Pt == ROOK) { - // 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]); + // Bonus for rook on the same file as a queen + if (file_bb(s) & pos.pieces(QUEEN)) + score += RookOnQueenFile; // Bonus for rook on an open or semi-open file if (pos.is_on_semiopen_file(Us, s)) - score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))]; + score += RookOnFile[pos.is_on_semiopen_file(Them, s)]; // Penalty when trapped by the king, even more if the king cannot castle else if (mob <= 3) @@ -388,7 +380,7 @@ namespace { constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); - Bitboard weak, b1, b2, safe, unsafeChecks = 0; + Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0; Bitboard rookChecks, queenChecks, bishopChecks, knightChecks; int kingDanger = 0; const Square ksq = pos.square(Us); @@ -447,27 +439,27 @@ namespace { else unsafeChecks |= knightChecks; - // Unsafe or occupied checking squares will also be considered, as long as - // the square is in the attacker's mobility area. - unsafeChecks &= mobilityArea[Them]; - - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. + // Find the squares that opponent attacks in our king flank, the squares + // which they attack twice in that flank, and the squares that we defend. b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; b2 = b1 & attackedBy2[Them]; + b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; - int kingFlankAttacks = popcount(b1) + popcount(b2); + int kingFlankAttack = popcount(b1) + popcount(b2); + int kingFlankDefense = popcount(b3); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 69 * kingAttacksCount[Them] + 185 * popcount(kingRing[Us] & weak) + + 148 * popcount(unsafeChecks) + + 98 * popcount(pos.blockers_for_king(Us)) + + 69 * kingAttacksCount[Them] + + 4 * (kingFlankAttack - kingFlankDefense) + + 3 * kingFlankAttack * kingFlankAttack / 8 + + mg_value(mobility[Them] - mobility[Us]) + - 873 * !pos.count(Them) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) - - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 - + mg_value(mobility[Them] - mobility[Us]) - + 5 * kingFlankAttacks * kingFlankAttacks / 16 - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation @@ -479,7 +471,7 @@ namespace { score -= PawnlessFlank; // Penalty if king flank is under attack, potentially moving toward the king - score -= FlankAttacks * kingFlankAttacks; + score -= FlankAttacks * kingFlankAttack; if (T) Trace::add(KING, Us, score); @@ -494,7 +486,7 @@ namespace { Score Evaluation::threats() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; @@ -514,29 +506,16 @@ 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) { b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]); while (b) - { - Square s = pop_lsb(&b); - score += ThreatByMinor[type_of(pos.piece_on(s))]; - if (type_of(pos.piece_on(s)) != PAWN) - score += ThreatByRank * (int)relative_rank(Them, s); - } + score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))]; 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); - } + score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))]; if (weak & attackedBy[Us][KING]) score += ThreatByKing; @@ -553,6 +532,14 @@ namespace { score += RestrictedPiece * popcount(b); + // Protected or unattacked squares + safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; + + // Bonus for attacking enemy pieces with our relatively safe pawns + b = pos.pieces(Us, PAWN) & safe; + b = pawn_attacks_bb(b) & nonPawnEnemies; + score += ThreatBySafePawn * popcount(b); + // Find squares where our pawns can push on the next move b = shift(pos.pieces(Us, PAWN)) & ~pos.pieces(); b |= shift(b & TRank3BB) & ~pos.pieces(); @@ -564,12 +551,6 @@ namespace { b = pawn_attacks_bb(b) & nonPawnEnemies; 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) { @@ -599,7 +580,7 @@ namespace { Score Evaluation::passed() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); auto king_proximity = [&](Color c, Square s) { return std::min(distance(pos.square(c), s), 5); @@ -642,7 +623,7 @@ namespace { bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); if (!(pos.pieces(Them) & bb)) - unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); + unsafeSquares &= attackedBy[Them][ALL_PIECES]; // If there are no enemy attacks on passed pawn span, assign a big bonus. // Otherwise assign a smaller bonus if the path to queen is not attacked @@ -666,7 +647,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus + PassedFile[file_of(s)]; + score += bonus - PassedFile * map_to_queenside(file_of(s)); } if (T) @@ -690,7 +671,7 @@ namespace { return SCORE_ZERO; constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = -pawn_push(Us); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); @@ -705,12 +686,10 @@ namespace { behind |= shift(behind); behind |= shift(behind); - int bonus = popcount(safe) + popcount(behind & safe); + int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); int weight = pos.count(Us) - 1; Score score = make_score(bonus * weight * weight / 16, 0); - score -= AttacksOnSpaceArea * popcount(attackedBy[Them][ALL_PIECES] & behind & safe); - if (T) Trace::add(SPACE, Us, score); @@ -723,7 +702,10 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Value eg) const { + Score Evaluation::initiative(Score score) const { + + Value mg = mg_value(score); + Value eg = eg_value(score); int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -731,23 +713,29 @@ namespace { bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); + bool almostUnwinnable = !pe->passed_count() + && outflanking < 0 + && !pawnsOnBothFlanks; + // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking - + 18 * pawnsOnBothFlanks - + 49 * !pos.non_pawn_material() - -103 ; - - // Now apply the bonus: note that we find the attacking side by extracting - // the sign of the endgame value, and that we carefully cap the bonus so - // that the endgame score will never change sign after the bonus. + + 21 * pawnsOnBothFlanks + + 51 * !pos.non_pawn_material() + - 43 * almostUnwinnable + - 95 ; + + // Now apply the bonus: note that we find the attacking side by extracting the + // sign of the midgame or endgame values, and that we carefully cap the bonus + // so that the midgame and endgame scores do not change sign after the bonus. + int u = ((mg > 0) - (mg < 0)) * std::max(std::min(complexity + 50, 0), -abs(mg)); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) - Trace::add(INITIATIVE, make_score(0, v)); + Trace::add(INITIATIVE, make_score(u, v)); - return make_score(0, v); + return make_score(u, v); } @@ -766,8 +754,9 @@ namespace { && pos.non_pawn_material() == 2 * BishopValueMg) sf = 16 + 4 * pe->passed_count(); else - sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); + sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); @@ -823,7 +812,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(eg_value(score)); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score));