X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=5d073b15756f42a929ec42d87753766050332a15;hp=ee98da90e60097714a132c70e50af020705e250f;hb=37e38639279bf58558b92932739da57e7c2e3bdc;hpb=e6f4b5f46344d638c5e3b27cdbc966899e80e8d6 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ee98da90..5d073b15 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -2,7 +2,7 @@ Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -114,11 +114,11 @@ namespace { // 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(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) + S(0, 0), S(5, 32), S(57, 41), S(77, 56), S(88, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(2, 44), S(36, 71), S(36, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -127,25 +127,26 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); - constexpr Score CorneredBishop = S( 50, 50); - constexpr Score FlankAttacks = S( 8, 0); - constexpr Score Hanging = S( 69, 36); - constexpr Score KingProtector = S( 7, 8); - constexpr Score KnightOnQueen = S( 16, 12); - constexpr Score LongDiagonalBishop = S( 45, 0); - constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 16, 5); - constexpr Score PassedFile = S( 11, 8); - constexpr Score PawnlessFlank = S( 17, 95); - constexpr Score RestrictedPiece = S( 7, 7); - 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 ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 47, 4); - constexpr Score WeakQueen = S( 49, 15); + constexpr Score BishopPawns = S( 3, 7); + constexpr Score CorneredBishop = S( 50, 50); + constexpr Score FlankAttacks = S( 8, 0); + constexpr Score Hanging = S( 69, 36); + constexpr Score KingProtector = S( 7, 8); + constexpr Score KnightOnQueen = S( 16, 12); + constexpr Score LongDiagonalBishop = S( 45, 0); + constexpr Score MinorBehindPawn = S( 18, 3); + constexpr Score Outpost = S( 30, 21); + constexpr Score PassedFile = S( 11, 8); + constexpr Score PawnlessFlank = S( 17, 95); + constexpr Score RestrictedPiece = S( 7, 7); + 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 ThreatBySafePawn = S(173, 94); + constexpr Score TrappedRook = S( 52, 10); + constexpr Score WeakQueen = S( 49, 15); + constexpr Score WeakQueenProtection = S( 14, 0); #undef S @@ -213,8 +214,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); @@ -224,9 +225,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 queen or controlled by - // enemy pawns are excluded from the mobility area. - mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); + // Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king + // or controlled by enemy pawns are excluded from the mobility area. + mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them)); // Initialize attackedBy[] for king and pawns attackedBy[Us][KING] = pos.attacks_from(ksq); @@ -235,15 +236,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(Utility::clamp(file_of(ksq), FILE_B, FILE_G), + Utility::clamp(rank_of(ksq), RANK_2, RANK_7)); + kingRing[Us] = PseudoAttacks[KING][s] | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -258,7 +253,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); @@ -298,11 +293,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); - - 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) score += MinorBehindPawn; @@ -322,20 +317,19 @@ namespace { // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) score += LongDiagonalBishop; - } - // 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. - if ( Pt == BISHOP - && pos.is_chess960() - && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) - { - 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)) ? CorneredBishop * 4 - : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 - : CorneredBishop; + // 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. + if ( pos.is_chess960() + && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) + { + 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)) ? CorneredBishop * 4 + : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 + : CorneredBishop; + } } } @@ -381,7 +375,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); @@ -440,25 +434,27 @@ namespace { else unsafeChecks |= knightChecks; - // 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) - - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) + + 69 * kingAttacksCount[Them] + + 3 * kingFlankAttack * kingFlankAttack / 8 + + mg_value(mobility[Them] - mobility[Us]) - 873 * !pos.count(Them) + - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 6 * mg_value(score) / 8 - + mg_value(mobility[Them] - mobility[Us]) - + 5 * kingFlankAttacks * kingFlankAttacks / 16 - - 7; + - 4 * kingFlankDefense + + 37; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 100) @@ -469,7 +465,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); @@ -484,7 +480,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; @@ -521,13 +517,15 @@ namespace { b = ~attackedBy[Them][ALL_PIECES] | (nonPawnEnemies & attackedBy2[Us]); score += Hanging * popcount(weak & b); + + // Additional bonus if weak piece is only protected by a queen + score += WeakQueenProtection * popcount(weak & attackedBy[Them][QUEEN]); } // Bonus for restricting their piece moves b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - score += RestrictedPiece * popcount(b); // Protected or unattacked squares @@ -578,7 +576,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); @@ -596,7 +594,6 @@ namespace { assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); int r = relative_rank(Us, s); - File f = file_of(s); Score bonus = PassedRank[r]; @@ -606,8 +603,8 @@ namespace { Square blockSq = s + Up; // Adjust bonus based on the king's proximity - bonus += make_score(0, ( king_proximity(Them, blockSq) * 5 - - king_proximity(Us, blockSq) * 2) * w); + bonus += make_score(0, ( (king_proximity(Them, blockSq) * 19) / 4 + - king_proximity(Us, blockSq) * 2) * w); // If blockSq is not the queening square then consider also a second push if (r != RANK_7) @@ -646,7 +643,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * map_to_queenside(f); + score += bonus - PassedFile * map_to_queenside(file_of(s)); } if (T) @@ -670,7 +667,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); @@ -703,9 +700,6 @@ namespace { template 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)); @@ -716,14 +710,21 @@ namespace { && outflanking < 0 && !pawnsOnBothFlanks; + bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 + || rank_of(pos.square(BLACK)) < RANK_5; + // 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() - - 36 * almostUnwinnable - -103 ; + + 21 * pawnsOnBothFlanks + + 24 * infiltration + + 51 * !pos.non_pawn_material() + - 43 * almostUnwinnable + -110 ; + + Value mg = mg_value(score); + Value eg = eg_value(score); // 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 @@ -751,11 +752,11 @@ namespace { { if ( pos.opposite_bishops() && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 16 + 4 * pe->passed_count(); + sf = 22 ; else sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); - sf = std::max(0, sf - (pos.rule50_count() - 12) / 4 ); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); @@ -830,8 +831,7 @@ namespace { Trace::add(TOTAL, score); } - return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view - + Eval::Tempo; + return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view } } // namespace @@ -851,6 +851,9 @@ Value Eval::evaluate(const Position& pos) { std::string Eval::trace(const Position& pos) { + if (pos.checkers()) + return "Total evaluation: none (in check)"; + std::memset(scores, 0, sizeof(scores)); pos.this_thread()->contempt = SCORE_ZERO; // Reset any dynamic contempt