X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=47a65c592cdfb7ef3456f27e99cca109ebb5ae0d;hp=031b803417c4c4832f7b6fe5bdb2a3d26618f724;hb=be6fafd0793d934c31925832b4bde569b5abd5b9;hpb=043a469f83b4c81f94ab991029b4cd49fb05452e diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 031b8034..47a65c59 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] << " " @@ -102,7 +111,8 @@ namespace { Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO }; // attackedBy[color][piece type] is a bitboard representing all squares - // attacked by a given color and piece type (can be also ALL_PIECES). + // attacked by a given color and piece type. Special "piece types" which are + // also calculated are QUEEN_DIAGONAL and ALL_PIECES. Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; // attackedBy2[color] are the squares attacked by 2 pieces of a given color, @@ -202,22 +212,23 @@ namespace { const Score KingProtector[] = { S(-3, -5), S(-4, -3), S(-3, 0), S(-1, 1) }; // Assorted bonuses and penalties used by evaluation - const Score MinorBehindPawn = S( 16, 0); - const Score BishopPawns = S( 8, 12); - const Score RookOnPawn = S( 8, 24); - const Score TrappedRook = S( 92, 0); - const Score WeakQueen = S( 50, 10); - const Score OtherCheck = S( 10, 10); - 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 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); - const Score TrappedBishopA1H1 = S( 50, 50); + 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); + const Score CloseEnemies = S( 7, 0); + const Score PawnlessFlank = S( 20, 80); + const Score ThreatByHangingPawn = S( 71, 61); + 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 ThreatByAttackOnQueen = S( 38, 22); + const Score HinderPassedPawn = S( 7, 0); + const Score TrappedBishopA1H1 = S( 50, 50); #undef S #undef V @@ -226,10 +237,10 @@ namespace { const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 }; // Penalties for enemy's safe checks - const int QueenCheck = 780; - const int RookCheck = 880; - const int BishopCheck = 435; - const int KnightCheck = 790; + const int QueenSafeCheck = 780; + const int RookSafeCheck = 880; + const int BishopSafeCheck = 435; + const int KnightSafeCheck = 790; // Threshold for lazy and space evaluation const Value LazyThreshold = Value(1500); @@ -242,9 +253,9 @@ namespace { template template void Evaluation::initialize() { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Square Up = (Us == WHITE ? NORTH : SOUTH); - const Square Down = (Us == WHITE ? SOUTH : NORTH); + 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); // Find our pawns on the first two ranks, and those which are blocked @@ -293,6 +304,9 @@ 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,6 +320,9 @@ namespace { attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b; attackedBy[Us][ALL_PIECES] |= attackedBy[Us][Pt] |= b; + if (Pt == QUEEN) + attackedBy[Us][QUEEN_DIAGONAL] |= b & PseudoAttacks[BISHOP][s]; + if (b & kingRing[Them]) { kingAttackersCount[Us]++; @@ -325,12 +342,12 @@ namespace { // Bonus for outpost squares bb = OutpostRanks & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & s)] * 2; + score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2; else { bb &= b & ~pos.pieces(Us); if (bb) - score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & bb)]; + score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)]; } // Bonus when behind a pawn @@ -338,10 +355,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. @@ -349,7 +372,7 @@ namespace { && pos.is_chess960() && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) { - Square d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); + 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 @@ -365,7 +388,7 @@ namespace { // Bonus when on an open or semi-open file if (pe->semiopen_file(Us, file_of(s))) - score += RookOnFile[!!pe->semiopen_file(Them, file_of(s))]; + score += RookOnFile[bool(pe->semiopen_file(Them, file_of(s)))]; // Penalty when trapped by the king, even more if the king cannot castle else if (mob <= 3) @@ -396,25 +419,15 @@ 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 ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB - : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); + const Color Them = (Us == WHITE ? BLACK : WHITE); + const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB + : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); const Square ksq = pos.square(Us); - Bitboard kingOnlyDefended, undefended, b, b1, b2, safe, other; - int kingDanger; + Bitboard weak, b, b1, b2, safe, unsafeChecks; // King shelter and enemy pawns storm Score score = pe->king_safety(pos, ksq); @@ -422,74 +435,57 @@ namespace { // Main king safety evaluation if (kingAttackersCount[Them] > (1 - pos.count(Them))) { - // Find the attacked squares which are defended only by our king... - kingOnlyDefended = attackedBy[Them][ALL_PIECES] - & attackedBy[Us][KING] - & ~attackedBy2[Us]; - - // ... and those which are not defended at all in the larger king ring - 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 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] - + 191 * popcount(kingOnlyDefended | undefended) - + 143 * !!pos.pinned_pieces(Us) - - 848 * !pos.count(Them) - - 9 * mg_value(score) / 8 - + 40; + // Attacked squares defended at most once by our queen or king + weak = attackedBy[Them][ALL_PIECES] + & ~attackedBy2[Us] + & (attackedBy[Us][KING] | attackedBy[Us][QUEEN] | ~attackedBy[Us][ALL_PIECES]); + + int kingDanger = unsafeChecks = 0; // Analyse the safe enemy's checks which are possible on next move safe = ~pos.pieces(Them); - safe &= ~attackedBy[Us][ALL_PIECES] | (kingOnlyDefended & attackedBy2[Them]); + safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]); - b1 = pos.attacks_from< ROOK>(ksq); - b2 = pos.attacks_from(ksq); + b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); + b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); // Enemy queen safe checks - if ((b1 | b2) & attackedBy[Them][QUEEN] & safe) - kingDanger += QueenCheck; - - // For minors and rooks, also consider the square safe if attacked twice, - // and only defended by our queen. - safe |= attackedBy2[Them] - & ~(attackedBy2[Us] | pos.pieces(Them)) - & attackedBy[Us][QUEEN]; + if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN]) + kingDanger += QueenSafeCheck; - // Some other potential checks are also analysed, even from squares - // currently occupied by the opponent own pieces, as long as the square - // is not attacked by our pawns, and is not occupied by a blocked pawn. - other = ~( attackedBy[Us][PAWN] - | (pos.pieces(Them, PAWN) & shift(pos.pieces(PAWN)))); + b1 &= attackedBy[Them][ROOK]; + b2 &= attackedBy[Them][BISHOP]; - // Enemy rooks safe and other checks - if (b1 & attackedBy[Them][ROOK] & safe) - kingDanger += RookCheck; + // Enemy rooks checks + if (b1 & safe) + kingDanger += RookSafeCheck; + else + unsafeChecks |= b1; - else if (b1 & attackedBy[Them][ROOK] & other) - score -= OtherCheck; + // Enemy bishops checks + if (b2 & safe) + kingDanger += BishopSafeCheck; + else + unsafeChecks |= b2; - // Enemy bishops safe and other checks - if (b2 & attackedBy[Them][BISHOP] & safe) - kingDanger += BishopCheck; - - else if (b2 & attackedBy[Them][BISHOP] & other) - score -= OtherCheck; - - // Enemy knights safe and other checks + // Enemy knights checks b = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; if (b & safe) - kingDanger += KnightCheck; - - else if (b & other) - score -= OtherCheck; + kingDanger += KnightSafeCheck; + else + unsafeChecks |= b; + + // Unsafe or occupied checking squares will also be considered, as long as + // the square is in the attacker's mobility area. + unsafeChecks &= mobilityArea[Them]; + + kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] + + 102 * kingAdjacentZoneAttacksCount[Them] + + 191 * popcount(kingRing[Us] & weak) + + 143 * popcount(pos.pinned_pieces(Us) | unsafeChecks) + - 848 * !pos.count(Them) + - 9 * mg_value(score) / 8 + + 40; // Transform the kingDanger units into a Score, and substract it from the evaluation if (kingDanger > 0) @@ -527,11 +523,11 @@ namespace { template template Score Evaluation::evaluate_threats() { - const Color Them = (Us == WHITE ? BLACK : WHITE); - 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 TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); + 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); Bitboard b, weak, defended, stronglyProtected, safeThreats; Score score = SCORE_ZERO; @@ -613,6 +609,13 @@ namespace { score += ThreatByPawnPush * popcount(b); + // Add a bonus for safe slider attack threats on opponent 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]); + + score += ThreatByAttackOnQueen * popcount(b & safeThreats); + if (T) Trace::add(THREAT, Us, score); @@ -626,8 +629,8 @@ namespace { template template Score Evaluation::evaluate_passed_pawns() { - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Square Up = (Us == WHITE ? NORTH : SOUTH); + const Color Them = (Us == WHITE ? BLACK : WHITE); + const Direction Up = (Us == WHITE ? NORTH : SOUTH); Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; Score score = SCORE_ZERO; @@ -767,6 +770,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); } @@ -827,7 +833,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(); + Score score = pos.psq_score() + me->imbalance() + Eval::Contempt; // Probe the pawn hash table pe = Pawns::probe(pos); @@ -890,6 +896,7 @@ namespace { } // namespace +Score Eval::Contempt = SCORE_ZERO; /// evaluate() is the evaluator for the outer world. It returns a static evaluation /// of the position from the point of view of the side to move. @@ -927,6 +934,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);