X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=d7b83057ff7c2ddb5108f708faed601ae12dd407;hp=2169a1ac8995d9d37474e6289c00302708ffd3c0;hb=c053f0b838662b2c6fd32beb3999b11c2c968ad9;hpb=b95b1a970510b74dc567824ff428362e17e39066 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2169a1ac..d7b83057 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -130,28 +130,22 @@ namespace { V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 }; - // ThreatBonus[][] contains bonus according to which piece type - // attacks which one. - #define Z S(0, 0) - + // ThreatBonus[attacking][attacked] contains bonus according to which + // piece type attacks which one. const Score ThreatBonus[8][8] = { - { Z, Z, Z, Z, Z, Z, Z, Z }, // not used - { Z, S(18,37), Z, S(37,47), S(55,97), S(55,97), Z, Z }, // KNIGHT attacks - { Z, S(18,37), S(37,47), Z, S(55,97), S(55,97), Z, Z }, // BISHOP attacks - { Z, S( 9,27), S(27,47), S(27,47), Z, S(37,47), Z, Z }, // ROOK attacks - { Z, S(27,37), S(27,37), S(27,37), S(27,37), Z, Z, Z }, // QUEEN attacks - { Z, Z, Z, Z, Z, Z, Z, Z }, // not used - { Z, Z, Z, Z, Z, Z, Z, Z }, // not used - { Z, Z, Z, Z, Z, Z, Z, Z } // not used + {}, {}, + { S(0, 0), S(18,37), S( 0, 0), S(37,47), S(55,97), S(55,97) }, // KNIGHT + { S(0, 0), S(18,37), S(37,47), S( 0, 0), S(55,97), S(55,97) }, // BISHOP + { S(0, 0), S( 9,27), S(27,47), S(27,47), S( 0, 0), S(37,47) }, // ROOK + { S(0, 0), S(27,37), S(27,37), S(27,37), S(27,37), S( 0, 0) } // QUEEN }; // ThreatedByPawnPenalty[] contains a penalty according to which piece // type is attacked by an enemy pawn. const Score ThreatedByPawnPenalty[8] = { - Z, Z, S(56, 70), S(56, 70), S(76, 99), S(86, 118), Z, Z + S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118) }; - #undef Z #undef S // Bonus for unstoppable passed pawns @@ -208,13 +202,8 @@ namespace { /// the strength of the enemy attack are added up into an integer, which /// is used as an index to KingDangerTable[]. - // Attack weights for each piece type and table indexed on piece type - const int QueenAttackWeight = 5; - const int RookAttackWeight = 3; - const int BishopAttackWeight = 2; - const int KnightAttackWeight = 2; - - const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight }; + // KingAttackWeights[] contains king attack weights by piece type + const int KingAttackWeights[8] = { 0, 0, 2, 2, 3, 5 }; // Bonuses for enemy's safe checks const int QueenContactCheckBonus = 3; @@ -224,12 +213,6 @@ namespace { const int BishopCheckBonus = 1; const int KnightCheckBonus = 1; - // Scan for queen contact mates? - const bool QueenContactMates = true; - - // Bonus for having a mate threat - const int MateThreatBonus = 3; - // InitKingDanger[] contains bonuses based on the position of the defending // king. const int InitKingDanger[64] = { @@ -428,11 +411,7 @@ Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) { } // Interpolate between the middle game and the endgame score - Color stm = pos.side_to_move(); - - Value v = Sign[stm] * scale_by_game_phase(ei.value, phase, factor); - - return (ei.mateThreat[stm] == MOVE_NONE ? v : 8 * QueenValueMidgame - v); + return Sign[pos.side_to_move()] * scale_by_game_phase(ei.value, phase, factor); } } // namespace @@ -559,7 +538,7 @@ namespace { if (b & ei.kingZone[Us]) { ei.kingAttackersCount[Us]++; - ei.kingAttackersWeight[Us] += AttackWeight[Piece]; + ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; Bitboard bb = (b & ei.attackedBy[Them][KING]); if (bb) ei.kingAdjacentZoneAttacksCount[Us] += count_1s_max_15(bb); @@ -705,10 +684,9 @@ namespace { const Color Them = (Us == WHITE ? BLACK : WHITE); - Bitboard undefended, attackedByOthers, escapeSquares, occ, b, b1, b2, safe; - Square from, to; + Bitboard undefended, b, b1, b2, safe; bool sente; - int attackUnits, count, shelter = 0; + int attackUnits, shelter = 0; const Square ksq = pos.king_square(Us); // King shelter @@ -721,129 +699,84 @@ namespace { // King safety. This is quite complicated, and is almost certainly far // from optimally tuned. if ( pos.piece_count(Them, QUEEN) >= 1 - && ei.kingAttackersCount[Them] >= 2 - && pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame + && ei.kingAttackersCount[Them] >= 2 + && pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame && ei.kingAdjacentZoneAttacksCount[Them]) { - // Is it the attackers turn to move? - sente = (Them == pos.side_to_move()); - - // Find the attacked squares around the king which has no defenders - // apart from the king itself - undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING); - undefended &= ~( ei.attacked_by(Us, PAWN) | ei.attacked_by(Us, KNIGHT) - | ei.attacked_by(Us, BISHOP) | ei.attacked_by(Us, ROOK) - | ei.attacked_by(Us, QUEEN)); - - // Initialize the 'attackUnits' variable, which is used later on as an - // index to the KingDangerTable[] array. The initial value is based on - // the number and types of the enemy's attacking pieces, the number of - // attacked and undefended squares around our king, the square of the - // king, and the quality of the pawn shelter. - attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) - + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15(undefended)) - + InitKingDanger[relative_square(Us, ksq)] - - (shelter >> 5); - - // Analyse safe queen contact checks - b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them); - if (b) - { - attackedByOthers = ei.attacked_by(Them, PAWN) | ei.attacked_by(Them, KNIGHT) - | ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK); + // Is it the attackers turn to move? + sente = (Them == pos.side_to_move()); + + // Find the attacked squares around the king which has no defenders + // apart from the king itself + undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING); + undefended &= ~( ei.attacked_by(Us, PAWN) | ei.attacked_by(Us, KNIGHT) + | ei.attacked_by(Us, BISHOP) | ei.attacked_by(Us, ROOK) + | ei.attacked_by(Us, QUEEN)); + + // Initialize the 'attackUnits' variable, which is used later on as an + // index to the KingDangerTable[] array. The initial value is based on + // the number and types of the enemy's attacking pieces, the number of + // attacked and undefended squares around our king, the square of the + // king, and the quality of the pawn shelter. + attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) + + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15(undefended)) + + InitKingDanger[relative_square(Us, ksq)] + - shelter / 32; + + // Analyse enemy's safe queen contact checks. First find undefended + // squares around the king attacked by enemy queen... + b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them); + if (b) + { + // ...then remove squares not supported by another enemy piece + b &= ( ei.attacked_by(Them, PAWN) | ei.attacked_by(Them, KNIGHT) + | ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK)); + if (b) + attackUnits += QueenContactCheckBonus * count_1s_max_15(b) * (sente ? 2 : 1); + } + + // Analyse enemy's safe distance checks for sliders and knights + safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us)); - b &= attackedByOthers; + b1 = pos.attacks_from(ksq) & safe; + b2 = pos.attacks_from(ksq) & safe; - // Squares attacked by the queen and supported by another enemy piece and - // not defended by other pieces but our king. + // Enemy queen safe checks + b = (b1 | b2) & ei.attacked_by(Them, QUEEN); if (b) - { - // The bitboard b now contains the squares available for safe queen - // contact checks. - count = count_1s_max_15(b); - attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1); + attackUnits += QueenCheckBonus * count_1s_max_15(b); - // Is there a mate threat? - if (QueenContactMates && !pos.is_check()) - { - escapeSquares = pos.attacks_from(ksq) & ~pos.pieces_of_color(Us) & ~attackedByOthers; - occ = pos.occupied_squares(); - while (b) - { - to = pop_1st_bit(&b); - - // Do we have escape squares from queen contact check attack ? - if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[ksq]))) - { - // We have a mate, unless the queen is pinned or there - // is an X-ray attack through the queen. - for (int i = 0; i < pos.piece_count(Them, QUEEN); i++) - { - from = pos.piece_list(Them, QUEEN, i); - if ( bit_is_set(pos.attacks_from(from), to) - && !bit_is_set(pos.pinned_pieces(Them), from) - && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & pos.pieces(ROOK, QUEEN, Us)) - && !(bishop_attacks_bb(to, occ & ClearMaskBB[from]) & pos.pieces(BISHOP, QUEEN, Us))) - - // Set the mate threat move - ei.mateThreat[Them] = make_move(from, to); - } - } - } - } - } - } + // Enemy rooks safe checks + b = b1 & ei.attacked_by(Them, ROOK); + if (b) + attackUnits += RookCheckBonus * count_1s_max_15(b); + + // Enemy bishops safe checks + b = b2 & ei.attacked_by(Them, BISHOP); + if (b) + attackUnits += BishopCheckBonus * count_1s_max_15(b); - // Analyse enemy's safe distance checks - safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us)); - - b1 = pos.attacks_from(ksq) & safe; - b2 = pos.attacks_from(ksq) & safe; - - // Enemy rooks safe checks - b = b1 & ei.attacked_by(Them, ROOK); - if (b) - attackUnits += RookCheckBonus * count_1s_max_15(b); - - // Enemy bishops safe checks - b = b2 & ei.attacked_by(Them, BISHOP); - if (b) - attackUnits += BishopCheckBonus * count_1s_max_15(b); - - // Enemy queens safe checks - b = (b1 | b2) & ei.attacked_by(Them, QUEEN); - if (b) - attackUnits += QueenCheckBonus * count_1s_max_15(b); - - // Enemy knights safe checks - b = pos.attacks_from(ksq) & ei.attacked_by(Them, KNIGHT) & safe; - if (b) - attackUnits += KnightCheckBonus * count_1s_max_15(b); - - // Analyse discovered checks (only for non-pawns right now, consider - // adding pawns later). - b = pos.discovered_check_candidates(Them) & ~pos.pieces(PAWN); - if (b) - attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente ? 2 : 1); - - // Has a mate threat been found? We don't do anything here if the - // side with the mating move is the side to move, because in that - // case the mating side will get a huge bonus at the end of the main - // evaluation function instead. - if (ei.mateThreat[Them] != MOVE_NONE) - attackUnits += MateThreatBonus; - - // Ensure that attackUnits is between 0 and 99, in order to avoid array - // out of bounds errors. - attackUnits = Min(99, Max(0, attackUnits)); - - // Finally, extract the king danger score from the KingDangerTable[] - // array and subtract the score from evaluation. Set also ei.kingDanger[] - // value that will be used for pruning because this value can sometimes - // be very big, and so capturing a single attacking piece can therefore - // result in a score change far bigger than the value of the captured piece. - ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits]; - ei.kingDanger[Us] = mg_value(KingDangerTable[Us][attackUnits]); + // Enemy knights safe checks + b = pos.attacks_from(ksq) & ei.attacked_by(Them, KNIGHT) & safe; + if (b) + attackUnits += KnightCheckBonus * count_1s_max_15(b); + + // Analyse enemy's discovered checks (only for non-pawns right now, + // consider adding pawns later). + b = pos.discovered_check_candidates(Them) & ~pos.pieces(PAWN); + if (b) + attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente ? 2 : 1); + + // To index KingDangerTable[] attackUnits must be in [0, 99] range + attackUnits = Min(99, Max(0, attackUnits)); + + // Finally, extract the king danger score from the KingDangerTable[] + // array and subtract the score from evaluation. Set also ei.kingDanger[] + // value that will be used for pruning because this value can sometimes + // be very big, and so capturing a single attacking piece can therefore + // result in a score change far bigger than the value of the captured piece. + ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits]; + ei.kingDanger[Us] = mg_value(KingDangerTable[Us][attackUnits]); } }