X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=a0ad09f084baea61e850e478dc4666d7a097c44b;hp=b58d4a03dca3b7d291a6a84fbc49ccbd7174e198;hb=80d59eea392fc073f6d0ba29cb9a97e3d705ee58;hpb=64a6138d3736babad0f0d9758e3d0e5475f477dd diff --git a/src/evaluate.cpp b/src/evaluate.cpp index b58d4a03..a0ad09f0 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -73,28 +73,17 @@ 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 LazyThreshold = Value(1400); constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10 }; + constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; // 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,60 +106,46 @@ 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) }; + constexpr Score RookOnFile[] = { S(21, 4), S(47, 25) }; // 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. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(0, 31), S(39, 42), S(57, 44), S(68, 112), S(62, 120) + S(0, 0), S(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(0, 24), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250) - }; - - // PassedFile[File] contains a bonus according to the file of a passed pawn - constexpr Score PassedFile[FILE_NB] = { - S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14), - S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7) + S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; // 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( 32, 10); + constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnPawn = S( 10, 32); + 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 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); #undef S @@ -192,7 +167,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Value eg) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@ -205,15 +180,12 @@ namespace { // 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, - // possibly via x-ray or by one pawn and one piece. Diagonal x-ray through - // pawn or squares attacked by 2 pawns are not explicitly added. + // attackedBy2[color] are the squares attacked by at least 2 units of a given + // color, including x-rays. But diagonal x-rays through pawns are not computed. Bitboard attackedBy2[COLOR_NB]; - // 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. + // kingRing[color] are the squares adjacent to the king plus some other + // very near squares, depending on king position. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color @@ -243,40 +215,41 @@ namespace { 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); + constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); + + const Square ksq = pos.square(Us); + + Bitboard dblAttackByPawn = pawn_double_attacks_bb(pos.pieces(Us, PAWN)); // 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]; + attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); - kingRing[Us] = kingAttackersCount[Them] = 0; + // Init our king safety tables + kingRing[Us] = attackedBy[Us][KING]; + if (relative_rank(Us, ksq) == RANK_1) + kingRing[Us] |= shift(kingRing[Us]); - // Init our king safety tables only if we are going to use them - if (pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg) - { - kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, pos.square(Us)) == RANK_1) - kingRing[Us] |= shift(kingRing[Us]); + if (file_of(ksq) == FILE_H) + kingRing[Us] |= shift(kingRing[Us]); - if (file_of(pos.square(Us)) == FILE_H) - kingRing[Us] |= shift(kingRing[Us]); + else if (file_of(ksq) == FILE_A) + kingRing[Us] |= shift(kingRing[Us]); - else if (file_of(pos.square(Us)) == FILE_A) - kingRing[Us] |= shift(kingRing[Us]); + kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); + kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; - 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] &= ~dblAttackByPawn; } @@ -291,12 +264,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)) @@ -324,12 +296,12 @@ namespace { if (Pt == BISHOP || Pt == KNIGHT) { // Bonus if piece is on an outpost square or can reach one - bb = OutpostRanks & ~pe->pawn_attacks_span(Them); + bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2; + score += Outpost * (Pt == KNIGHT ? 2 : 1); - else if (bb &= b & ~pos.pieces(Us)) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)]; + 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) @@ -344,7 +316,7 @@ namespace { // bishop, bigger when the center files are blocked with pawns. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); - score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s) + score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) * (1 + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares @@ -369,20 +341,20 @@ namespace { if (Pt == ROOK) { - // Bonus for aligning rook with enemy pawns on the same rank/file - if (relative_rank(Us, s) >= RANK_5) - score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); + // Bonus for rook on the same file as a queen + if (file_bb(s) & pos.pieces(QUEEN)) + score += RookOnQueenFile; // Bonus for rook on an open or semi-open file - if (pe->semiopen_file(Us, file_of(s))) - score += RookOnFile[bool(pe->semiopen_file(Them, file_of(s)))]; + if (pos.is_on_semiopen_file(Us, s)) + score += RookOnFile[pos.is_on_semiopen_file(Them, s)]; // Penalty when trapped by the king, even more if the king cannot castle else if (mob <= 3) { 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)); } } @@ -409,89 +381,95 @@ 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]; + // Attacked squares defended at most once by our queen or king + weak = attackedBy[Them][ALL_PIECES] + & ~attackedBy2[Us] + & (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]); - int tropism = popcount(b1) + popcount(b2); + // Analyse the safe enemy's checks which are possible on next move + safe = ~pos.pieces(Them); + safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]); - // Main king safety evaluation - if (kingAttackersCount[Them] > 1 - pos.count(Them)) - { - int kingDanger = 0; - unsafeChecks = 0; - - // Attacked squares defended at most once by our queen or king - weak = attackedBy[Them][ALL_PIECES] - & ~attackedBy2[Us] - & (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]); + b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); + b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Analyse the safe enemy's checks which are possible on next move - safe = ~pos.pieces(Them); - safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]); + // Enemy rooks checks + rookChecks = b1 & safe & attackedBy[Them][ROOK]; - 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; + if (rookChecks) + kingDanger += RookSafeCheck; + else + unsafeChecks |= b1 & attackedBy[Them][ROOK]; + + // 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 & attackedBy[Them][BISHOP]; - b1 &= attackedBy[Them][ROOK]; - b2 &= attackedBy[Them][BISHOP]; + // Enemy knights checks + knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - // Enemy rooks checks - if (b1 & safe) - kingDanger += RookSafeCheck; - else - unsafeChecks |= b1; + if (knightChecks & safe) + kingDanger += KnightSafeCheck; + else + unsafeChecks |= knightChecks; - // Enemy bishops checks - if (b2 & safe) - kingDanger += BishopSafeCheck; - else - unsafeChecks |= b2; + // 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]; - // Enemy knights checks - b = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - if (b & safe) - 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] - + 69 * kingAttacksCount[Them] - + 185 * popcount(kingRing[Us] & weak) - + 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; - - // Transform the kingDanger units into a Score, and subtract it from the evaluation - if (kingDanger > 0) - score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); - } + 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]) + - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) + + 148 * popcount(unsafeChecks) + + 98 * popcount(pos.blockers_for_king(Us)) + - 873 * !pos.count(Them) + - 6 * mg_value(score) / 8 + + mg_value(mobility[Them] - mobility[Us]) + + 3 * kingFlankAttacks * kingFlankAttacks / 8 + - 7; + + // Transform the kingDanger units into a Score, and subtract it from the evaluation + if (kingDanger > 100) + 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); @@ -509,11 +487,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. @@ -526,29 +504,16 @@ namespace { // Enemies not strongly protected and under our attack weak = pos.pieces(Them) & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - // Safe or protected squares - safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; - // Bonus according to the kind of attacking pieces if (defended | weak) { b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]); while (b) - { - Square s = pop_lsb(&b); - score += ThreatByMinor[type_of(pos.piece_on(s))]; - if (type_of(pos.piece_on(s)) != PAWN) - score += ThreatByRank * (int)relative_rank(Them, s); - } + score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))]; b = weak & attackedBy[Us][ROOK]; while (b) - { - Square s = pop_lsb(&b); - score += ThreatByRook[type_of(pos.piece_on(s))]; - if (type_of(pos.piece_on(s)) != PAWN) - score += ThreatByRank * (int)relative_rank(Them, s); - } + score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))]; if (weak & attackedBy[Us][KING]) score += ThreatByKing; @@ -559,15 +524,19 @@ namespace { } // Bonus for restricting their piece moves - restricted = attackedBy[Them][ALL_PIECES] - & ~attackedBy[Them][PAWN] - & ~attackedBy2[Them] - & attackedBy[Us][ALL_PIECES]; - score += RestrictedPiece * popcount(restricted); + b = attackedBy[Them][ALL_PIECES] + & ~stronglyProtected + & attackedBy[Us][ALL_PIECES]; - // Bonus for enemy unopposed weak pawns - if (pos.pieces(Us, ROOK, QUEEN)) - score += WeakUnopposedPawn * pe->weak_unopposed(Them); + score += RestrictedPiece * popcount(b); + + // Protected or unattacked squares + safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; + + // Bonus for attacking enemy pieces with our relatively safe pawns + b = pos.pieces(Us, PAWN) & safe; + b = pawn_attacks_bb(b) & nonPawnEnemies; + score += ThreatBySafePawn * popcount(b); // Find squares where our pawns can push on the next move b = shift(pos.pieces(Us, PAWN)) & ~pos.pieces(); @@ -577,14 +546,8 @@ namespace { b &= ~attackedBy[Them][PAWN] & safe; // Bonus for safe pawn threats on the next move - b = pawn_attacks_bb(b) & pos.pieces(Them); - score += ThreatByPawnPush * popcount(b); - - // Our safe or protected pawns - b = pos.pieces(Us, PAWN) & safe; - b = pawn_attacks_bb(b) & nonPawnEnemies; - score += ThreatBySafePawn * popcount(b); + score += ThreatByPawnPush * popcount(b); // Bonus for threats on the next moves against enemy queen if (pos.count(Them) == 1) @@ -621,7 +584,7 @@ namespace { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; + Bitboard b, bb, squaresToQueen, unsafeSquares; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); @@ -633,12 +596,13 @@ 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]; if (r > RANK_3) { - int w = (r-2) * (r-2) + 2; + int w = 5 * r - 13; Square blockSq = s + Up; // Adjust bonus based on the king's proximity @@ -652,42 +616,37 @@ namespace { // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) { - // 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_file_bb(Us, s); - - bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from(s); + squaresToQueen = forward_file_bb(Us, s); + unsafeSquares = passed_pawn_span(Us, s); - if (!(pos.pieces(Us) & bb)) - defendedSquares &= attackedBy[Us][ALL_PIECES]; + bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); if (!(pos.pieces(Them) & bb)) - unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); - - // If there aren't any enemy attacks, assign a big bonus. Otherwise - // assign a smaller bonus if the block square isn't attacked. - int k = !unsafeSquares ? 20 : !(unsafeSquares & blockSq) ? 9 : 0; + unsafeSquares &= attackedBy[Them][ALL_PIECES]; - // If the path to the queen is fully defended, assign a big bonus. - // Otherwise assign a smaller bonus if the block square is defended. - if (defendedSquares == squaresToQueen) - k += 6; + // If there are no enemy attacks on passed pawn span, assign a big bonus. + // Otherwise assign a smaller bonus if the path to queen is not attacked + // and even smaller bonus if it is attacked but block square is not. + int k = !unsafeSquares ? 35 : + !(unsafeSquares & squaresToQueen) ? 20 : + !(unsafeSquares & blockSq) ? 9 : + 0 ; - else if (defendedSquares & blockSq) - k += 4; + // Assign a larger bonus if the block square is defended + if ((pos.pieces(Us) & bb) || (attackedBy[Us][ALL_PIECES] & blockSq)) + k += 5; bonus += make_score(k * w, k * w); } - } // rank > RANK_3 + } // r > RANK_3 // 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 + Up) - || (pos.pieces(PAWN) & forward_file_bb(Us, s))) + || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus + PassedFile[file_of(s)]; + score += bonus - PassedFile * map_to_queenside(f); } if (T) @@ -710,7 +669,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); @@ -722,12 +682,11 @@ 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); - - int bonus = popcount(safe) + popcount(behind & safe); - int weight = pos.count(Us) - 2 * pe->open_files(); + behind |= shift(behind); + behind |= shift(behind); + int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); + int weight = pos.count(Us) - 1; Score score = make_score(bonus * weight * weight / 16, 0); if (T) @@ -742,7 +701,10 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Value eg) const { + 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)); @@ -750,23 +712,29 @@ namespace { bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); + bool almostUnwinnable = !pe->passed_count() + && outflanking < 0 + && !pawnsOnBothFlanks; + // 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 ; - - // 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 complexity = 9 * pe->passed_count() + + 11 * pos.count() + + 9 * outflanking + + 18 * pawnsOnBothFlanks + + 49 * !pos.non_pawn_material() + - 36 * almostUnwinnable + -103 ; + + // 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 + // so that the midgame and endgame scores do not change sign after the bonus. + int u = ((mg > 0) - (mg < 0)) * std::max(std::min(complexity + 50, 0), -abs(mg)); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) - Trace::add(INITIATIVE, make_score(0, v)); + Trace::add(INITIATIVE, make_score(u, v)); - return make_score(0, v); + return make_score(u, v); } @@ -782,12 +750,12 @@ namespace { if (sf == SCALE_FACTOR_NORMAL) { if ( pos.opposite_bishops() - && pos.non_pawn_material(WHITE) == BishopValueMg - && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = 8 + 4 * pe->pawn_asymmetry(); + && pos.non_pawn_material() == 2 * BishopValueMg) + sf = 16 + 4 * pe->passed_count(); else - sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); + sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4 ); } return ScaleFactor(sf); @@ -822,7 +790,7 @@ namespace { // Early exit if score is high Value v = (mg_value(score) + eg_value(score)) / 2; - if (abs(v) > LazyThreshold) + if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; // Main evaluation begins here @@ -843,14 +811,14 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(eg_value(score)); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); 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) @@ -898,7 +866,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) @@ -909,6 +876,7 @@ std::string Eval::trace(const Position& pos) { << " Threats | " << Term(THREAT) << " Passed | " << Term(PASSED) << " Space | " << Term(SPACE) + << " Initiative | " << Term(INITIATIVE) << " ------------+-------------+-------------+------------\n" << " Total | " << Term(TOTAL);