X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=c50d14c21aac50605e6a58d87fddbe83d49e285f;hp=2a52ba1c5bb0b3ac686f1e880635937edb5543af;hb=f0f6da2d30fc005fd0fa126ee1eefd11fe10a604;hpb=67f5f54a29b5d5d2bd9e43bfcc3a95bcc142d664 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2a52ba1c..c50d14c2 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -74,35 +74,35 @@ using namespace Trace; namespace { - const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; - const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; - const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; - const Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); + constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; + constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; + constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; + constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); - const Bitboard KingFlank[FILE_NB] = { + constexpr Bitboard KingFlank[FILE_NB] = { QueenSide, QueenSide, QueenSide, CenterFiles, CenterFiles, KingSide, KingSide, KingSide }; // Threshold for lazy and space evaluation - const Value LazyThreshold = Value(1500); - const Value SpaceThreshold = Value(12222); + constexpr Value LazyThreshold = Value(1500); + constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 }; + constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 }; // Penalties for enemy's safe checks - const int QueenSafeCheck = 780; - const int RookSafeCheck = 880; - const int BishopSafeCheck = 435; - const int KnightSafeCheck = 790; + constexpr int QueenSafeCheck = 780; + constexpr int RookSafeCheck = 880; + constexpr int BishopSafeCheck = 435; + constexpr int KnightSafeCheck = 790; #define S(mg, eg) make_score(mg, eg) // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. - const Score MobilityBonus[][32] = { + constexpr Score MobilityBonus[][32] = { { S(-75,-76), S(-57,-54), S( -9,-28), S( -2,-10), S( 6, 5), S( 14, 12), // Knights S( 22, 26), S( 29, 29), S( 36, 29) }, { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops @@ -121,64 +121,66 @@ namespace { // Outpost[knight/bishop][supported by pawn] contains bonuses for minor // pieces if they occupy or can reach an outpost square, bigger if that // square is supported by a pawn. - const Score Outpost[][2] = { + constexpr Score Outpost[][2] = { { S(22, 6), S(36,12) }, // Knight { S( 9, 2), S(15, 5) } // Bishop }; // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. - const Score RookOnFile[] = { S(20, 7), S(45, 20) }; + constexpr Score RookOnFile[] = { S(20, 7), S(45, 20) }; // 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. - const Score ThreatByMinor[PIECE_TYPE_NB] = { + constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { S(0, 0), S(0, 31), S(39, 42), S(57, 44), S(68, 112), S(47, 120) }; - const Score ThreatByRook[PIECE_TYPE_NB] = { + constexpr Score ThreatByRook[PIECE_TYPE_NB] = { 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. - const Score ThreatByKing[] = { S(3, 65), S(9, 145) }; + constexpr Score ThreatByKing[] = { S(3, 65), S(9, 145) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn - const Score PassedRank[RANK_NB] = { + 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) }; // PassedFile[File] contains a bonus according to the file of a passed pawn - const Score PassedFile[FILE_NB] = { + 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) }; // PassedDanger[Rank] contains a term to weight the passed score - const int PassedDanger[RANK_NB] = { 0, 0, 0, 2, 7, 12, 19 }; + constexpr int PassedDanger[RANK_NB] = { 0, 0, 0, 2, 7, 12, 19 }; // KingProtector[PieceType-2] contains a penalty according to distance from king - const Score KingProtector[] = { S(3, 5), S(4, 3), S(3, 0), S(1, -1) }; + constexpr Score KingProtector[] = { S(3, 5), S(4, 3), S(3, 0), S(1, -1) }; // Assorted bonuses and penalties - const Score BishopPawns = S( 8, 12); - const Score CloseEnemies = S( 7, 0); - const Score Hanging = S( 52, 30); - const Score HinderPassedPawn = S( 8, 1); - const Score LongRangedBishop = S( 22, 0); - const Score MinorBehindPawn = S( 16, 0); - const Score PawnlessFlank = S( 20, 80); - const Score RookOnPawn = S( 8, 24); - const Score ThreatByPawnPush = S( 47, 26); - const Score ThreatByRank = S( 16, 3); - const Score ThreatBySafePawn = S(175,168); - const Score ThreatOnQueen = S( 42, 21); - const Score TrappedBishopA1H1 = S( 50, 50); - const Score TrappedRook = S( 92, 0); - const Score WeakQueen = S( 50, 10); - const Score WeakUnopposedPawn = S( 5, 25); + constexpr Score BishopPawns = S( 8, 12); + constexpr Score CloseEnemies = S( 7, 0); + constexpr Score Connectivity = S( 3, 1); + constexpr Score CorneredBishop = S( 50, 50); + constexpr Score Hanging = S( 52, 30); + constexpr Score HinderPassedPawn = S( 8, 1); + 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 SliderOnQueen = S( 42, 21); + constexpr Score ThreatByPawnPush = S( 47, 26); + constexpr Score ThreatByRank = S( 16, 3); + constexpr Score ThreatBySafePawn = S(175,168); + constexpr Score TrappedRook = S( 92, 0); + constexpr Score WeakQueen = S( 50, 10); + constexpr Score WeakUnopposedPawn = S( 5, 25); #undef S @@ -210,7 +212,7 @@ namespace { // attackedBy[color][piece type] is a bitboard representing all squares // attacked by a given color and piece type. Special "piece types" which - // are also calculated are QUEEN_DIAGONAL and ALL_PIECES. + // is also calculated is ALL_PIECES. Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; // attackedBy2[color] are the squares attacked by 2 pieces of a given color, @@ -228,18 +230,18 @@ namespace { // which attack a square in the kingRing of the enemy king. int kingAttackersCount[COLOR_NB]; - // kingAttackersWeight[color] is the sum of the "weights" of the pieces of the - // given color which attack a square in the kingRing of the enemy king. The - // weights of the individual piece types are given by the elements in the - // KingAttackWeights array. + // kingAttackersWeight[color] is the sum of the "weights" of the pieces of + // the given color which attack a square in the kingRing of the enemy king. + // The weights of the individual piece types are given by the elements in + // the KingAttackWeights array. int kingAttackersWeight[COLOR_NB]; - // kingAdjacentZoneAttacksCount[color] is the number of attacks by the given - // color to squares directly adjacent to the enemy king. Pieces which attack - // more than one square are counted multiple times. For instance, if there is + // kingAttacksCount[color] is the number of attacks by the given color to + // squares directly adjacent to the enemy king. Pieces which attack more + // than one square are counted multiple times. For instance, if there is // a white knight on g5 and black's king is on g8, this white knight adds 2 - // to kingAdjacentZoneAttacksCount[WHITE]. - int kingAdjacentZoneAttacksCount[COLOR_NB]; + // to kingAttacksCount[WHITE]. + int kingAttacksCount[COLOR_NB]; }; @@ -248,10 +250,10 @@ namespace { template template void Evaluation::initialize() { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Direction Up = (Us == WHITE ? NORTH : SOUTH); - const Direction Down = (Us == WHITE ? SOUTH : NORTH); - const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB); // Find our pawns that are blocked or on the first two ranks Bitboard b = pos.pieces(Us, PAWN) & (shift(pos.pieces()) | LowRanks); @@ -273,8 +275,14 @@ namespace { if (relative_rank(Us, pos.square(Us)) == RANK_1) kingRing[Us] |= shift(kingRing[Us]); + 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(attackedBy[Us][KING] & pe->pawn_attacks(Them)); - kingAdjacentZoneAttacksCount[Them] = kingAttackersWeight[Them] = 0; + kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; } else kingRing[Us] = kingAttackersCount[Them] = 0; @@ -285,9 +293,9 @@ namespace { template template Score Evaluation::pieces() { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB - : Rank5BB | Rank4BB | Rank3BB); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB + : Rank5BB | Rank4BB | Rank3BB); const Square* pl = pos.squares(Us); Bitboard b, bb; @@ -296,9 +304,6 @@ namespace { attackedBy[Us][Pt] = 0; - if (Pt == QUEEN) - attackedBy[Us][QUEEN_DIAGONAL] = 0; - while ((s = *pl++) != SQ_NONE) { // Find attacked squares, including x-ray attacks for bishops and rooks @@ -306,21 +311,18 @@ namespace { : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK)) : pos.attacks_from(s); - if (pos.pinned_pieces(Us) & s) + if (pos.blockers_for_king(Us) & s) b &= LineBB[pos.square(Us)][s]; attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b; attackedBy[Us][Pt] |= b; attackedBy[Us][ALL_PIECES] |= b; - if (Pt == QUEEN) - attackedBy[Us][QUEEN_DIAGONAL] |= b & PseudoAttacks[BISHOP][s]; - if (b & kingRing[Them]) { kingAttackersCount[Us]++; kingAttackersWeight[Us] += KingAttackWeights[Pt]; - kingAdjacentZoneAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); + kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } int mob = popcount(b & mobilityArea[Us]); @@ -352,7 +354,7 @@ namespace { // 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))) - score += LongRangedBishop; + score += LongDiagonalBishop; } // An important Chess960 pattern: A cornered bishop blocked by a friendly @@ -364,9 +366,9 @@ namespace { { Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); if (pos.piece_on(s + d) == make_piece(Us, PAWN)) - score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4 - : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2 - : TrappedBishopA1H1; + score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 + : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 + : CorneredBishop; } } @@ -392,8 +394,8 @@ namespace { if (Pt == QUEEN) { // Penalty if any relative pin or discovered attack against the queen - Bitboard pinners; - if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, pinners)) + Bitboard queenPinners; + if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners)) score -= WeakQueen; } } @@ -408,12 +410,12 @@ namespace { template template Score Evaluation::king() const { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); const Square ksq = pos.square(Us); - Bitboard weak, b, b1, b2, safe, unsafeChecks; + Bitboard weak, b, b1, b2, safe, unsafeChecks, pinned; // King shelter and enemy pawns storm Score score = pe->king_safety(pos, ksq); @@ -421,7 +423,8 @@ namespace { // Main king safety evaluation if (kingAttackersCount[Them] > 1 - pos.count(Them)) { - int kingDanger = unsafeChecks = 0; + int kingDanger = 0; + unsafeChecks = 0; // Attacked squares defended at most once by our queen or king weak = attackedBy[Them][ALL_PIECES] @@ -464,11 +467,12 @@ 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 * kingAdjacentZoneAttacksCount[Them] + + 102 * kingAttacksCount[Them] + 191 * popcount(kingRing[Us] & weak) - + 143 * popcount(pos.pinned_pieces(Us) | unsafeChecks) + + 143 * popcount(pinned | unsafeChecks) - 848 * !pos.count(Them) - 9 * mg_value(score) / 8 + 40; @@ -481,22 +485,20 @@ namespace { score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); } } - // Penalty when our king is on a pawnless flank - if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)])) - score -= PawnlessFlank; - // King tropism: firstly, find attacked squares in our king flank - b = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; + Bitboard kf = KingFlank[file_of(ksq)]; - assert(((Us == WHITE ? b << 4 : b >> 4) & b) == 0); - assert(popcount(Us == WHITE ? b << 4 : b >> 4) == popcount(b)); + // Penalty when our king is on a pawnless flank + if (!(pos.pieces(PAWN) & kf)) + score -= PawnlessFlank; - // Secondly, add the squares which are attacked twice in that flank and - // which are not defended by our pawns. - b = (Us == WHITE ? b << 4 : b >> 4) - | (b & attackedBy2[Them] & ~attackedBy[Us][PAWN]); + // 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]; - score -= CloseEnemies * popcount(b); + // King tropism, to anticipate slow motion attacks on our king + score -= CloseEnemies * (popcount(b1) + popcount(b2)); if (T) Trace::add(KING, Us, score); @@ -510,11 +512,9 @@ namespace { template template Score Evaluation::threats() const { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Direction Up = (Us == WHITE ? NORTH : SOUTH); - const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); - const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); - const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safeThreats; Score score = SCORE_ZERO; @@ -529,7 +529,7 @@ namespace { b = pos.pieces(Us, PAWN) & (~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]); - safeThreats = (shift(b) | shift(b)) & weak; + safeThreats = pawn_attacks_bb(b) & weak; score += ThreatBySafePawn * popcount(safeThreats); } @@ -585,18 +585,31 @@ namespace { & (attackedBy[Us][ALL_PIECES] | ~attackedBy[Them][ALL_PIECES]); // Bonus for safe pawn threats on the next move - b = (shift(b) | shift(b)) + b = pawn_attacks_bb(b) & pos.pieces(Them) & ~attackedBy[Us][PAWN]; score += ThreatByPawnPush * popcount(b); - // Bonus for safe slider threats on the next move toward enemy queen - safeThreats = ~pos.pieces(Us) & ~attackedBy2[Them] & attackedBy2[Us]; - b = (attackedBy[Us][BISHOP] & attackedBy[Them][QUEEN_DIAGONAL]) - | (attackedBy[Us][ROOK ] & attackedBy[Them][QUEEN] & ~attackedBy[Them][QUEEN_DIAGONAL]); + // Bonus for threats on the next moves against enemy queen + if (pos.count(Them) == 1) + { + Square s = pos.square(Them); + safeThreats = mobilityArea[Us] & ~stronglyProtected; + + b = attackedBy[Us][KNIGHT] & pos.attacks_from(s); + + score += KnightOnQueen * popcount(b & safeThreats); + + b = (attackedBy[Us][BISHOP] & pos.attacks_from(s)) + | (attackedBy[Us][ROOK ] & pos.attacks_from(s)); - score += ThreatOnQueen * popcount(b & safeThreats); + score += SliderOnQueen * popcount(b & safeThreats & 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); @@ -610,8 +623,8 @@ namespace { template template Score Evaluation::passed() const { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); auto king_proximity = [&](Color c, Square s) { return std::min(distance(pos.square(c), s), 5); @@ -708,8 +721,8 @@ namespace { template template Score Evaluation::space() const { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Bitboard SpaceMask = + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); @@ -729,12 +742,9 @@ namespace { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - // Since SpaceMask[Us] is fully on our half of the board... - assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0); - - // ...count safe + (behind & safe) with a single popcount. - int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe)); + int bonus = popcount(safe) + popcount(behind & safe); int weight = pos.count(Us) - 2 * pe->open_files(); + Score score = make_score(bonus * weight * weight / 16, 0); if (T) @@ -758,16 +768,17 @@ namespace { && (pos.pieces(PAWN) & KingSide); // Compute the initiative bonus for the attacking side - int initiative = 8 * outflanking + int complexity = 8 * outflanking + 8 * pe->pawn_asymmetry() + 12 * pos.count() + 16 * pawnsOnBothFlanks + + 48 * !pos.non_pawn_material() -136 ; // 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. - int v = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg)); + int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) Trace::add(INITIATIVE, make_score(0, v)); @@ -881,7 +892,8 @@ namespace { Trace::add(TOTAL, score); } - return pos.side_to_move() == WHITE ? v : -v; // Side to move point of view + return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view + + Eval::Tempo; } } // namespace @@ -891,7 +903,7 @@ namespace { /// evaluation of the position from the point of view of the side to move. Value Eval::evaluate(const Position& pos) { - return Evaluation(pos).value() + Eval::Tempo; + return Evaluation(pos).value(); } @@ -905,7 +917,7 @@ std::string Eval::trace(const Position& pos) { Eval::Contempt = SCORE_ZERO; // Reset any dynamic contempt - Value v = Evaluation(pos).value() + Eval::Tempo; + Value v = Evaluation(pos).value(); v = pos.side_to_move() == WHITE ? v : -v; // Trace scores are from white's point of view