X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=b1a85a0fcb67cb1692db334b09d437fca3ee356f;hp=0f2744d9e4ec42abd243b45527d2ff16dff0537a;hb=1d09ee70f7da1f9aa60c7ff97a35881327f69a03;hpb=c73706243672bf36b0fef58e817f843cb341d8ca diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0f2744d9..b1a85a0f 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -77,6 +77,11 @@ namespace { // attacked by a given color and piece type (can be also 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. + Bitboard attackedBy2[COLOR_NB]; + // kingRing[color] is the zone around the king which is considered // by the king safety evaluation. This consists of the squares directly // adjacent to the king, and the three (or two, for a king on an edge file) @@ -183,9 +188,11 @@ namespace { const Score BishopPawns = S( 8, 12); const Score RookOnPawn = S( 8, 24); const Score TrappedRook = S(92, 0); - const Score Checked = S(20, 20); + const Score SafeCheck = S(20, 20); + const Score OtherCheck = S(10, 10); const Score ThreatByHangingPawn = S(71, 61); const Score LooseEnemies = S( 0, 25); + const Score WeakQueen = S(35, 0); const Score Hanging = S(48, 27); const Score ThreatByPawnPush = S(38, 22); const Score Unstoppable = S( 0, 20); @@ -209,10 +216,10 @@ namespace { // Penalties for enemy's safe checks const int QueenContactCheck = 89; - const int QueenCheck = 52; - const int RookCheck = 45; - const int BishopCheck = 5; - const int KnightCheck = 17; + const int QueenCheck = 62; + const int RookCheck = 57; + const int BishopCheck = 48; + const int KnightCheck = 78; // eval_init() initializes king and attack bitboards for a given color @@ -225,9 +232,10 @@ namespace { const Square Down = (Us == WHITE ? DELTA_S : DELTA_N); ei.pinnedPieces[Us] = pos.pinned_pieces(Us); - Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.square(Them)); + Bitboard b = ei.attackedBy[Them][KING]; ei.attackedBy[Them][ALL_PIECES] |= b; ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); + ei.attackedBy2[Us] = ei.attackedBy[Us][PAWN] & ei.attackedBy[Us][KING]; // Init king safety tables only if we are going to use them if (pos.non_pawn_material(Us) >= QueenValueMg) @@ -270,6 +278,7 @@ namespace { if (ei.pinnedPieces[Us] & s) b &= LineBB[pos.square(Us)][s]; + ei.attackedBy2[Us] |= ei.attackedBy[Us][ALL_PIECES] & b; ei.attackedBy[Us][ALL_PIECES] |= ei.attackedBy[Us][Pt] |= b; if (b & ei.kingRing[Them]) @@ -346,6 +355,13 @@ namespace { score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us)); } } + + if (Pt == QUEEN) + { + // Penalty if any relative pin or discovered attack against the queen + if (pos.slider_blockers(pos.pieces(), pos.pieces(Them, ROOK, BISHOP), s)) + score -= WeakQueen; + } } if (DoTrace) @@ -366,9 +382,10 @@ namespace { template Score evaluate_king(const Position& pos, const EvalInfo& ei) { - const Color Them = (Us == WHITE ? BLACK : WHITE); + const Color Them = (Us == WHITE ? BLACK : WHITE); + const Square Up = (Us == WHITE ? DELTA_N : DELTA_S); - Bitboard undefended, b, b1, b2, safe; + Bitboard undefended, b, b1, b2, safe, other; int attackUnits; const Square ksq = pos.square(Us); @@ -379,11 +396,9 @@ namespace { if (ei.kingAttackersCount[Them]) { // Find the attacked squares which are defended only by the king... - undefended = ei.attackedBy[Them][ALL_PIECES] - & ei.attackedBy[Us][KING] - & ~( ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] - | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK] - | ei.attackedBy[Us][QUEEN]); + undefended = ei.attackedBy[Them][ALL_PIECES] + & ei.attackedBy[Us][KING] + & ~ei.attackedBy2[Us]; // ... and those which are not defended at all in the larger king ring b = ei.attackedBy[Them][ALL_PIECES] & ~ei.attackedBy[Us][ALL_PIECES] @@ -396,45 +411,60 @@ namespace { // the pawn shelter (current 'score' value). attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) + 9 * ei.kingAdjacentZoneAttacksCount[Them] - + 27 * popcount(undefended) - + 11 * (popcount(b) + !!ei.pinnedPieces[Us]) + + 21 * popcount(undefended) + + 12 * (popcount(b) + !!ei.pinnedPieces[Us]) - 64 * !pos.count(Them) - mg_value(score) / 8; // Analyse the enemy's safe queen contact checks. Firstly, find the // undefended squares around the king reachable by the enemy queen... b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them); - if (b) - { - // ...and then remove squares not supported by another enemy piece - b &= ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT] - | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK] - | ei.attackedBy[Them][KING]; - attackUnits += QueenContactCheck * popcount(b); - } + // ...and keep squares supported by another enemy piece + attackUnits += QueenContactCheck * popcount(b & ei.attackedBy2[Them]); - // Analyse the enemy's safe distance checks for sliders and knights - safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them)); + // Analyse the safe enemy's checks which are possible on next move... + safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them)); - b1 = pos.attacks_from(ksq) & safe; - b2 = pos.attacks_from(ksq) & safe; + // ... and some other potential checks, only requiring the square to be + // safe from pawn-attacks, and not being occupied by a blocked pawn. + other = ~( ei.attackedBy[Us][PAWN] + | (pos.pieces(Them, PAWN) & shift_bb(pos.pieces(PAWN)))); + + b1 = pos.attacks_from(ksq); + b2 = pos.attacks_from(ksq); // Enemy queen safe checks - if ((b1 | b2) & ei.attackedBy[Them][QUEEN]) - attackUnits += QueenCheck, score -= Checked; + if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe) + attackUnits += QueenCheck, score -= SafeCheck; + + // For other pieces, also consider the square safe if attacked twice, + // and only defended by a queen. + safe |= ei.attackedBy2[Them] + & ~(ei.attackedBy2[Us] | pos.pieces(Them)) + & ei.attackedBy[Us][QUEEN]; - // Enemy rooks safe checks - if (b1 & ei.attackedBy[Them][ROOK]) - attackUnits += RookCheck, score -= Checked; + // Enemy rooks safe and other checks + if (b1 & ei.attackedBy[Them][ROOK] & safe) + attackUnits += RookCheck, score -= SafeCheck; - // Enemy bishops safe checks - if (b2 & ei.attackedBy[Them][BISHOP]) - attackUnits += BishopCheck, score -= Checked; + else if (b1 & ei.attackedBy[Them][ROOK] & other) + score -= OtherCheck; - // Enemy knights safe checks - if (pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe) - attackUnits += KnightCheck, score -= Checked; + // Enemy bishops safe and other checks + if (b2 & ei.attackedBy[Them][BISHOP] & safe) + attackUnits += BishopCheck, score -= SafeCheck; + + else if (b2 & ei.attackedBy[Them][BISHOP] & other) + score -= OtherCheck; + + // Enemy knights safe and other checks + b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT]; + if (b & safe) + attackUnits += KnightCheck, score -= SafeCheck; + + else if (b & other) + score -= OtherCheck; // Finally, extract the king danger score from the KingDanger[] // array and subtract the score from the evaluation. @@ -461,6 +491,18 @@ namespace { const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); + const Bitboard TheirCamp = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB + : Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB); + + const Bitboard QueenSide = TheirCamp & (FileABB | FileBBB | FileCBB | FileDBB); + const Bitboard CenterFiles = TheirCamp & (FileCBB | FileDBB | FileEBB | FileFBB); + const Bitboard KingSide = TheirCamp & (FileEBB | FileFBB | FileGBB | FileHBB); + + const Bitboard KingFlank[FILE_NB] = { + QueenSide, QueenSide, QueenSide, CenterFiles, + CenterFiles, KingSide, KingSide, KingSide + }; + enum { Minor, Rook }; Bitboard b, weak, defended, safeThreats; @@ -528,6 +570,18 @@ namespace { score += ThreatByPawnPush * popcount(b); + // King tropism: firstly, find squares that we attack in the enemy king flank + b = ei.attackedBy[Us][ALL_PIECES] & KingFlank[file_of(pos.square(Them))]; + + // Secondly, add to the bitboard the squares which we attack twice in that flank + // but which are not protected by a enemy pawn. Note the trick to shift away the + // previous attack bits to the empty part of the bitboard. + b = (b & ei.attackedBy2[Us] & ~ei.attackedBy[Them][PAWN]) + | (Us == WHITE ? b >> 4 : b << 4); + + // Count all these squares with a single popcount + score += make_score(7 * popcount(b), 0); + if (DoTrace) Trace::add(THREAT, Us, score); @@ -552,6 +606,7 @@ namespace { Square s = pop_lsb(&b); assert(pos.pawn_passed(Us, s)); + assert(!(pos.pieces(PAWN) & forward_bb(Us, s))); int r = relative_rank(Us, s) - RANK_2; int rr = r * (r - 1); @@ -697,7 +752,7 @@ namespace { // Endgame with opposite-colored bishops, but also other pieces. Still // a bit drawish, but not as drawish as with only the two bishops. else - sf = ScaleFactor(46 * sf / SCALE_FACTOR_NORMAL); + sf = ScaleFactor(46); } // Endings where weaker side can place his king in front of the opponent's // pawns are drawish. @@ -744,6 +799,8 @@ Value Eval::evaluate(const Position& pos) { // Initialize attack and king safety bitboards ei.attackedBy[WHITE][ALL_PIECES] = ei.attackedBy[BLACK][ALL_PIECES] = 0; + ei.attackedBy[WHITE][KING] = pos.attacks_from(pos.square(WHITE)); + ei.attackedBy[BLACK][KING] = pos.attacks_from(pos.square(BLACK)); eval_init(pos, ei); eval_init(pos, ei);