X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fevaluate.cpp;h=ee93f11f13cda2b3e776221282534969c18512ed;hb=0dc3b0978dca0459ceb483ada3792080f4caad15;hp=4e998bd4c32f4debc9f8a419cd8ce436ae285168;hpb=612d93234bdfbac77bba9c7a5756a92b76181ddf;p=stockfish diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4e998bd4..ee93f11f 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -31,12 +31,21 @@ namespace { + const Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); + const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; + const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; + const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; + + const Bitboard KingFlank[FILE_NB] = { + QueenSide, QueenSide, QueenSide, CenterFiles, CenterFiles, KingSide, KingSide, KingSide + }; + namespace Trace { enum Tracing {NO_TRACE, TRACE}; enum Term { // The first 8 entries are for PieceType - MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB + MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB }; double scores[TERM_NB][COLOR_NB][PHASE_NB]; @@ -54,7 +63,7 @@ namespace { std::ostream& operator<<(std::ostream& os, Term t) { - if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL) + if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == INITIATIVE || t == TOTAL) os << " --- --- | --- --- | "; else os << std::setw(5) << scores[t][WHITE][MG] << " " @@ -78,7 +87,7 @@ namespace { public: Evaluation() = delete; - Evaluation(const Position& p) : pos(p) {}; + Evaluation(const Position& p) : pos(p) {} Evaluation& operator=(const Evaluation&) = delete; Value value(); @@ -88,7 +97,7 @@ namespace { template void initialize(); template Score evaluate_king(); template Score evaluate_threats(); - template Score evaluate_passer_pawns(); + template Score evaluate_passed_pawns(); template Score evaluate_space(); template Score evaluate_pieces(); ScaleFactor evaluate_scale_factor(Value eg); @@ -162,8 +171,8 @@ namespace { // supported by a pawn. If the minor piece occupies an outpost square // then score is doubled. const Score Outpost[][2] = { - { S(22, 6), S(33, 9) }, // Knight - { S( 9, 2), S(14, 4) } // Bishop + { 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 @@ -204,6 +213,7 @@ namespace { // Assorted bonuses and penalties used by evaluation const Score MinorBehindPawn = S( 16, 0); const Score BishopPawns = S( 8, 12); + const Score LongRangedBishop = S( 22, 0); const Score RookOnPawn = S( 8, 24); const Score TrappedRook = S( 92, 0); const Score WeakQueen = S( 50, 10); @@ -211,16 +221,13 @@ namespace { const Score CloseEnemies = S( 7, 0); const Score PawnlessFlank = S( 20, 80); const Score ThreatByHangingPawn = S( 71, 61); - const Score ThreatBySafePawn = S(182,175); + const Score ThreatBySafePawn = S(192,175); const Score ThreatByRank = S( 16, 3); const Score Hanging = S( 48, 27); + const Score WeakUnopposedPawn = S( 5, 25); const Score ThreatByPawnPush = S( 38, 22); const Score HinderPassedPawn = S( 7, 0); - - // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by - // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only - // happen in Chess960 games. - const Score TrappedBishopA1H1 = S(50, 50); + const Score TrappedBishopA1H1 = S( 50, 50); #undef S #undef V @@ -341,10 +348,16 @@ namespace { && (pos.pieces(PAWN) & (s + pawn_push(Us)))) score += MinorBehindPawn; - // Penalty for pawns on the same color square as the bishop if (Pt == BISHOP) + { + // Penalty for pawns on the same color square as the bishop score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s); + // 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; + } + // An important Chess960 pattern: A cornered bishop blocked by a friendly // pawn diagonally in front of it is a very serious problem, especially // when that pawn is also blocked. @@ -399,24 +412,16 @@ namespace { // evaluate_king() assigns bonuses and penalties to a king of a given color - const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; - const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; - const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; - - const Bitboard KingFlank[FILE_NB] = { - QueenSide, QueenSide, QueenSide, CenterFiles, CenterFiles, KingSide, KingSide, KingSide - }; - template template Score Evaluation::evaluate_king() { const Color Them = (Us == WHITE ? BLACK : WHITE); const Square Up = (Us == WHITE ? NORTH : SOUTH); - const Bitboard Camp = (Us == WHITE ? ~Bitboard(0) ^ Rank6BB ^ Rank7BB ^ Rank8BB - : ~Bitboard(0) ^ Rank1BB ^ Rank2BB ^ Rank3BB); + const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB + : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); const Square ksq = pos.square(Us); - Bitboard undefended, b, b1, b2, safe, other; + Bitboard kingOnlyDefended, undefended, b, b1, b2, safe, other; int kingDanger; // King shelter and enemy pawns storm @@ -426,30 +431,32 @@ namespace { if (kingAttackersCount[Them] > (1 - pos.count(Them))) { // Find the attacked squares which are defended only by our king... - undefended = attackedBy[Them][ALL_PIECES] - & attackedBy[Us][KING] - & ~attackedBy2[Us]; + kingOnlyDefended = attackedBy[Them][ALL_PIECES] + & attackedBy[Us][KING] + & ~attackedBy2[Us]; // ... and those which are not defended at all in the larger king ring - b = attackedBy[Them][ALL_PIECES] & ~attackedBy[Us][ALL_PIECES] - & kingRing[Us] & ~pos.pieces(Them); + undefended = attackedBy[Them][ALL_PIECES] + & ~attackedBy[Us][ALL_PIECES] + & kingRing[Us] + & ~pos.pieces(Them); // Initialize the 'kingDanger' variable, which will be transformed // later into a king danger score. The initial value is based on the // number and types of the enemy's attacking pieces, the number of - // attacked and undefended squares around our king and the quality of - // the pawn shelter (current 'score' value). + // attacked and weak squares around our king, the absence of queen and + // the quality of the pawn shelter (current 'score' value). kingDanger = kingAttackersCount[Them] * kingAttackersWeight[Them] + 102 * kingAdjacentZoneAttacksCount[Them] - + 201 * popcount(undefended) - + 143 * (popcount(b) + !!pos.pinned_pieces(Us)) + + 191 * popcount(kingOnlyDefended | undefended) + + 143 * !!pos.pinned_pieces(Us) - 848 * !pos.count(Them) - 9 * mg_value(score) / 8 + 40; // Analyse the safe enemy's checks which are possible on next move safe = ~pos.pieces(Them); - safe &= ~attackedBy[Us][ALL_PIECES] | (undefended & attackedBy2[Them]); + safe &= ~attackedBy[Us][ALL_PIECES] | (kingOnlyDefended & attackedBy2[Them]); b1 = pos.attacks_from< ROOK>(ksq); b2 = pos.attacks_from(ksq); @@ -532,8 +539,7 @@ namespace { const Square Up = (Us == WHITE ? NORTH : SOUTH); const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); - const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); - const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); + const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); Bitboard b, weak, defended, stronglyProtected, safeThreats; Score score = SCORE_ZERO; @@ -596,14 +602,19 @@ namespace { score += ThreatByKing[more_than_one(b)]; } - // Bonus if some pawns can safely push and attack an enemy piece - b = pos.pieces(Us, PAWN) & ~TRank7BB; - b = shift(b | (shift(b & TRank2BB) & ~pos.pieces())); + // Bonus for opponent unopposed weak pawns + if (pos.pieces(Us, ROOK, QUEEN)) + score += WeakUnopposedPawn * pe->weak_unopposed(Them); - b &= ~pos.pieces() - & ~attackedBy[Them][PAWN] + // 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(); + + // Keep only the squares which are not completely unsafe + b &= ~attackedBy[Them][PAWN] & (attackedBy[Us][ALL_PIECES] | ~attackedBy[Them][ALL_PIECES]); + // Add a bonus for each new pawn threats from those squares b = (shift(b) | shift(b)) & pos.pieces(Them) & ~attackedBy[Us][PAWN]; @@ -617,13 +628,14 @@ namespace { } - // evaluate_passer_pawns() evaluates the passed pawns and candidate passed + // evaluate_passed_pawns() evaluates the passed pawns and candidate passed // pawns of the given color. template template - Score Evaluation::evaluate_passer_pawns() { + Score Evaluation::evaluate_passed_pawns() { const Color Them = (Us == WHITE ? BLACK : WHITE); + const Square Up = (Us == WHITE ? NORTH : SOUTH); Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; Score score = SCORE_ZERO; @@ -634,9 +646,9 @@ namespace { { Square s = pop_lsb(&b); - assert(!(pos.pieces(Them, PAWN) & forward_bb(Us, s + pawn_push(Us)))); + assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); - bb = forward_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them)); + bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them)); score -= HinderPassedPawn * popcount(bb); int r = relative_rank(Us, s) - RANK_2; @@ -646,7 +658,7 @@ namespace { if (rr) { - Square blockSq = s + pawn_push(Us); + Square blockSq = s + Up; // Adjust bonus based on the king's proximity ebonus += distance(pos.square(Them), blockSq) * 5 * rr @@ -654,7 +666,7 @@ namespace { // If blockSq is not the queening square then consider also a second push if (relative_rank(Us, blockSq) != RANK_8) - ebonus -= distance(pos.square(Us), blockSq + pawn_push(Us)) * rr; + ebonus -= distance(pos.square(Us), blockSq + Up) * rr; // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) @@ -662,9 +674,9 @@ namespace { // If there is a rook or queen attacking/defending the pawn from behind, // consider all the squaresToQueen. Otherwise consider only the squares // in the pawn's path attacked or occupied by the enemy. - defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s); + defendedSquares = unsafeSquares = squaresToQueen = forward_file_bb(Us, s); - bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from(s); + bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from(s); if (!(pos.pieces(Us) & bb)) defendedSquares &= attackedBy[Us][ALL_PIECES]; @@ -692,7 +704,7 @@ namespace { // Scale down bonus for candidate passers which need more than one // pawn push to become passed or have a pawn in front of them. - if (!pos.pawn_passed(Us, s + pawn_push(Us)) || (pos.pieces(PAWN) & forward_bb(Us, s))) + if (!pos.pawn_passed(Us, s + Up) || (pos.pieces(PAWN) & forward_file_bb(Us, s))) mbonus /= 2, ebonus /= 2; score += make_score(mbonus, ebonus) + PassedFile[file_of(s)]; @@ -763,6 +775,9 @@ namespace { // that the endgame score will never change sign after the bonus. int v = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg)); + if (T) + Trace::add(INITIATIVE, make_score(0, v)); + return make_score(0, v); } @@ -852,8 +867,8 @@ namespace { score += evaluate_threats() - evaluate_threats(); - score += evaluate_passer_pawns() - - evaluate_passer_pawns(); + score += evaluate_passed_pawns() + - evaluate_passed_pawns(); if (pos.non_pawn_material() >= SpaceThreshold) score += evaluate_space() @@ -923,6 +938,7 @@ std::string Eval::trace(const Position& pos) { << " Threats | " << Term(THREAT) << " Passed pawns | " << Term(PASSED) << " Space | " << Term(SPACE) + << " Initiative | " << Term(INITIATIVE) << "----------------+-------------+-------------+-------------\n" << " Total | " << Term(TOTAL);