X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=deb8211ab7d5d86d3f214f0b9e5f11231d786ee6;hp=53a54006a7a6cf1afabd0d8a9989c3a7b0b5131b;hb=c8589903777b6e0289640b43fae966ded442af48;hpb=69dc5568b3bb9a02c71bdd5bb0e87135e892ea19 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 53a54006..deb8211a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include // For std::memset #include @@ -73,17 +72,6 @@ using namespace Trace; namespace { - 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); - - constexpr Bitboard KingFlank[FILE_NB] = { - QueenSide ^ FileDBB, QueenSide, QueenSide, - CenterFiles, CenterFiles, - KingSide, KingSide, KingSide ^ FileEBB - }; - // Threshold for lazy and space evaluation constexpr Value LazyThreshold = Value(1500); constexpr Value SpaceThreshold = Value(12222); @@ -93,8 +81,8 @@ namespace { // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 880; - constexpr int BishopSafeCheck = 435; + constexpr int RookSafeCheck = 1080; + constexpr int BishopSafeCheck = 635; constexpr int KnightSafeCheck = 790; #define S(mg, eg) make_score(mg, eg) @@ -117,14 +105,6 @@ namespace { S(106,184), S(109,191), S(113,206), S(116,212) } }; - // 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. - 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. constexpr Score RookOnFile[] = { S(18, 7), S(44, 20) }; @@ -153,13 +133,14 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); - constexpr Score CloseEnemies = S( 8, 0); 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( 9, 3); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnPawn = S( 10, 32); @@ -168,7 +149,7 @@ namespace { constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatByRank = S( 13, 0); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 96, 4); + constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); constexpr Score WeakUnopposedPawn = S( 12, 23); @@ -213,7 +194,7 @@ namespace { // kingRing[color] are the squares adjacent to the king, plus (only for a // king on its first rank) the squares two ranks in front. For instance, // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6 - // and h6. It is set to 0 when king safety evaluation is skipped. + // and h6. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color @@ -245,33 +226,37 @@ namespace { constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB); + const Square ksq = pos.square(Us); + // 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. + // 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)); - // Initialise attackedBy bitboards for kings and pawns - attackedBy[Us][KING] = pos.attacks_from(pos.square(Us)); + // Initialize attackedBy[] for king and pawns + attackedBy[Us][KING] = pos.attacks_from(ksq); attackedBy[Us][PAWN] = pe->pawn_attacks(Us); attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; attackedBy2[Us] = attackedBy[Us][KING] & attackedBy[Us][PAWN]; // Init our king safety tables kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, pos.square(Us)) == RANK_1) + if (relative_rank(Us, ksq) == RANK_1) kingRing[Us] |= shift(kingRing[Us]); - if (file_of(pos.square(Us)) == FILE_H) + if (file_of(ksq) == FILE_H) kingRing[Us] |= shift(kingRing[Us]); - else if (file_of(pos.square(Us)) == FILE_A) + else if (file_of(ksq) == FILE_A) kingRing[Us] |= shift(kingRing[Us]); kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); - kingRing[Us] &= ~double_pawn_attacks_bb(pos.pieces(Us, PAWN)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; + + // Remove from kingRing[] the squares defended by two pawns + kingRing[Us] &= ~pawn_double_attacks_bb(pos.pieces(Us, PAWN)); } @@ -286,12 +271,11 @@ namespace { const Square* pl = pos.squares(Us); Bitboard b, bb; - Square s; Score score = SCORE_ZERO; attackedBy[Us][Pt] = 0; - while ((s = *pl++) != SQ_NONE) + for (Square s = *pl; s != SQ_NONE; s = *++pl) { // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) @@ -321,10 +305,12 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2; + score += Outpost * (Pt == KNIGHT ? 4 : 2) + * (1 + bool(attackedBy[Us][PAWN] & s)); else if (bb &= b & ~pos.pieces(Us)) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)]; + score += Outpost * (Pt == KNIGHT ? 2 : 1) + * (1 + bool(attackedBy[Us][PAWN] & bb)); // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) @@ -377,7 +363,7 @@ namespace { { File kf = file_of(pos.square(Us)); if ((kf < FILE_E) == (file_of(s) < kf)) - score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.castling_rights(Us)); + score -= TrappedRook * (1 + !pos.castling_rights(Us)); } } @@ -404,24 +390,14 @@ namespace { constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); + Bitboard weak, b1, b2, safe, unsafeChecks = 0; + Bitboard rookChecks, queenChecks, bishopChecks, knightChecks; + int kingDanger = 0; const Square ksq = pos.square(Us); - Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks; - // King shelter and enemy pawns storm + // Init the score with king shelter and enemy pawns storm Score score = pe->king_safety(pos); - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. - kingFlank = KingFlank[file_of(ksq)]; - b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; - b2 = b1 & attackedBy2[Them]; - - int tropism = popcount(b1) + popcount(b2); - - // Main king safety evaluation - int kingDanger = 0; - unsafeChecks = 0; - // Attacked squares defended at most once by our queen or king weak = attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us] @@ -434,56 +410,77 @@ namespace { 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 & ~attackedBy[Us][QUEEN]) - kingDanger += QueenSafeCheck; - - b1 &= attackedBy[Them][ROOK]; - b2 &= attackedBy[Them][BISHOP]; - // Enemy rooks checks - if (b1 & safe) + rookChecks = b1 & safe & attackedBy[Them][ROOK]; + + if (rookChecks) kingDanger += RookSafeCheck; else - unsafeChecks |= b1; + unsafeChecks |= b1 & attackedBy[Them][ROOK]; - // Enemy bishops checks - if (b2 & safe) + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. + queenChecks = (b1 | b2) + & attackedBy[Them][QUEEN] + & safe + & ~attackedBy[Us][QUEEN] + & ~rookChecks; + + if (queenChecks) + kingDanger += QueenSafeCheck; + + // Enemy bishops checks: we count them only if they are from squares from + // which we can't give a queen check, because queen checks are more valuable. + bishopChecks = b2 + & attackedBy[Them][BISHOP] + & safe + & ~queenChecks; + + if (bishopChecks) kingDanger += BishopSafeCheck; else - unsafeChecks |= b2; + unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks - b = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - if (b & safe) + knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + + if (knightChecks & safe) kingDanger += KnightSafeCheck; else - unsafeChecks |= b; + 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. + b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; + b2 = b1 & attackedBy2[Them]; + + int kingFlankAttacks = popcount(b1) + popcount(b2); + kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] + 69 * kingAttacksCount[Them] + 185 * popcount(kingRing[Us] & weak) + - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) - + tropism * tropism / 4 - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) - - 30; + + 5 * kingFlankAttacks * kingFlankAttacks / 16 + - 25; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 0) score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); // Penalty when our king is on a pawnless flank - if (!(pos.pieces(PAWN) & kingFlank)) + if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)])) score -= PawnlessFlank; - // King tropism bonus, to anticipate slow motion attacks on our king - score -= CloseEnemies * tropism; + // Penalty if king flank is under attack, potentially moving toward the king + score -= FlankAttacks * kingFlankAttacks; if (T) Trace::add(KING, Us, score); @@ -501,11 +498,11 @@ namespace { constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe, restricted; + Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; Score score = SCORE_ZERO; // Non-pawn enemies - nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(Them, PAWN); + nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN); // Squares strongly protected by the enemy, either because they defend the // square with a pawn, or because they defend the square twice and we don't. @@ -551,10 +548,11 @@ namespace { } // Bonus for restricting their piece moves - restricted = attackedBy[Them][ALL_PIECES] - & ~stronglyProtected - & attackedBy[Us][ALL_PIECES]; - score += RestrictedPiece * popcount(restricted); + b = attackedBy[Them][ALL_PIECES] + & ~stronglyProtected + & attackedBy[Us][ALL_PIECES]; + + score += RestrictedPiece * popcount(b); // Bonus for enemy unopposed weak pawns if (pos.pieces(Us, ROOK, QUEEN)) @@ -701,7 +699,8 @@ namespace { if (pos.non_pawn_material() < SpaceThreshold) return SCORE_ZERO; - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); @@ -713,11 +712,12 @@ namespace { // Find all squares which are at most three squares behind some friendly pawn Bitboard behind = pos.pieces(Us, PAWN); - behind |= (Us == WHITE ? behind >> 8 : behind << 8); - behind |= (Us == WHITE ? behind >> 16 : behind << 16); + behind |= shift(behind); + behind |= shift(shift(behind)); int bonus = popcount(safe) + popcount(behind & safe); - int weight = pos.count(Us) - 2 * pe->open_files(); + int weight = pos.count(Us) + - 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]); Score score = make_score(bonus * weight * weight / 16, 0); @@ -742,12 +742,12 @@ namespace { && (pos.pieces(PAWN) & KingSide); // Compute the initiative bonus for the attacking side - int complexity = 8 * pe->pawn_asymmetry() - + 12 * pos.count() - + 12 * outflanking - + 16 * pawnsOnBothFlanks - + 48 * !pos.non_pawn_material() - -118 ; + 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 @@ -775,7 +775,7 @@ namespace { if ( pos.opposite_bishops() && pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = 8 + 4 * pe->pawn_asymmetry(); + sf = 16 + 4 * pe->passed_count(); else sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); @@ -841,7 +841,7 @@ namespace { v = mg_value(score) * int(me->game_phase()) + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; - v /= int(PHASE_MIDGAME); + v /= PHASE_MIDGAME; // In case of tracing add all remaining individual evaluation terms if (T) @@ -889,7 +889,6 @@ std::string Eval::trace(const Position& pos) { << " ------------+-------------+-------------+------------\n" << " Material | " << Term(MATERIAL) << " Imbalance | " << Term(IMBALANCE) - << " Initiative | " << Term(INITIATIVE) << " Pawns | " << Term(PAWN) << " Knights | " << Term(KNIGHT) << " Bishops | " << Term(BISHOP) @@ -900,6 +899,7 @@ std::string Eval::trace(const Position& pos) { << " Threats | " << Term(THREAT) << " Passed | " << Term(PASSED) << " Space | " << Term(SPACE) + << " Initiative | " << Term(INITIATIVE) << " ------------+-------------+-------------+------------\n" << " Total | " << Term(TOTAL);