X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=82bf7b06908a5db47820f0a52627991da6e2f5c2;hp=664f3e859f32ea3e77fa352fa576fba98137000f;hb=9d1522b24f24f0bb37425cb5bb2087d622faa58e;hpb=2a2353aac65d6f7263081dc373c768c8717602db diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 664f3e85..82bf7b06 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -45,6 +45,11 @@ namespace { // Pointer to pawn hash table entry PawnInfo* pi; + // updateKingTables[color] is set to true if we have enough material + // to trigger the opponent's king safety calculation. When is false we + // skip the time consuming update of the king attackers tables. + bool updateKingTables[2]; + // attackedBy[color][piece type] is a bitboard representing all squares // attacked by a given color and piece type, attackedBy[color][0] contains // all squares attacked by the given color. @@ -194,9 +199,10 @@ namespace { const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 }; // Bonuses for enemy's safe checks - const int QueenContactCheckBonus = 3; - const int QueenCheckBonus = 2; - const int RookCheckBonus = 1; + const int QueenContactCheckBonus = 6; + const int RookContactCheckBonus = 4; + const int QueenCheckBonus = 3; + const int RookCheckBonus = 2; const int BishopCheckBonus = 1; const int KnightCheckBonus = 1; @@ -224,7 +230,7 @@ namespace { // Function prototypes template - Value do_evaluate(const Position& pos, Value margins[]); + Value do_evaluate(const Position& pos, Value& margin); template void init_eval_info(const Position& pos, EvalInfo& ei); @@ -233,7 +239,7 @@ namespace { Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility); template - Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]); + Score evaluate_king(const Position& pos, EvalInfo& ei, Value& margin); template Score evaluate_threats(const Position& pos, EvalInfo& ei); @@ -267,16 +273,16 @@ void prefetchPawn(Key key, int threadID) { /// evaluate() is the main evaluation function. It always computes two /// values, an endgame score and a middle game score, and interpolates /// between them based on the remaining material. -Value evaluate(const Position& pos, Value margins[]) { +Value evaluate(const Position& pos, Value& margin) { - return CpuHasPOPCNT ? do_evaluate(pos, margins) - : do_evaluate(pos, margins); + return CpuHasPOPCNT ? do_evaluate(pos, margin) + : do_evaluate(pos, margin); } namespace { template -Value do_evaluate(const Position& pos, Value margins[]) { +Value do_evaluate(const Position& pos, Value& margin) { EvalInfo ei; ScaleFactor factor[2]; @@ -290,9 +296,9 @@ Value do_evaluate(const Position& pos, Value margins[]) { // in the position object (material + piece square tables). Score bonus = pos.value(); - // margins[color] is the uncertainty estimation of position's evaluation + // margin is the uncertainty estimation of position's evaluation // and typically is used by the search for pruning decisions. - margins[WHITE] = margins[BLACK] = VALUE_ZERO; + margin = VALUE_ZERO; // Probe the material hash table MaterialInfo* mi = MaterialTable[pos.thread()]->get_material_info(pos); @@ -323,8 +329,8 @@ Value do_evaluate(const Position& pos, Value margins[]) { // Evaluate kings after all other pieces because we need complete attack // information when computing the king safety evaluation. - bonus += evaluate_king(pos, ei, margins) - - evaluate_king(pos, ei, margins); + bonus += evaluate_king(pos, ei, margin) + - evaluate_king(pos, ei, margin); // Evaluate tactical threats, we need full attack information including king bonus += evaluate_threats(pos, ei) @@ -336,26 +342,11 @@ Value do_evaluate(const Position& pos, Value margins[]) { Phase phase = mi->game_phase(); - // Middle-game specific evaluation terms - if (phase > PHASE_ENDGAME) + // Evaluate space for both sides, only in middle-game. + if (phase > PHASE_ENDGAME && mi->space_weight() > 0) { - // Evaluate pawn storms in positions with opposite castling - if ( square_file(pos.king_square(WHITE)) >= FILE_E - && square_file(pos.king_square(BLACK)) <= FILE_D) - - bonus += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0); - - else if ( square_file(pos.king_square(WHITE)) <= FILE_D - && square_file(pos.king_square(BLACK)) >= FILE_E) - - bonus += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0); - - // Evaluate space for both sides - if (mi->space_weight() > 0) - { - int s = evaluate_space(pos, ei) - evaluate_space(pos, ei); - bonus += apply_weight(make_score(s * mi->space_weight(), 0), Weights[Space]); - } + int s = evaluate_space(pos, ei) - evaluate_space(pos, ei); + bonus += apply_weight(make_score(s * mi->space_weight(), 0), Weights[Space]); } // If we don't already have an unusual scale factor, check for opposite @@ -466,9 +457,13 @@ namespace { Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.king_square(Them)); ei.kingZone[Us] = (b | (Us == WHITE ? b >> 8 : b << 8)); ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); - b &= ei.attackedBy[Us][PAWN]; - ei.kingAttackersCount[Us] = b ? count_1s_max_15(b) / 2 : EmptyBoardBB; - ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = EmptyBoardBB; + ei.updateKingTables[Us] = pos.piece_count(Us, QUEEN) && pos.non_pawn_material(Us) >= QueenValueMidgame + RookValueMidgame; + if (ei.updateKingTables[Us]) + { + b &= ei.attackedBy[Us][PAWN]; + ei.kingAttackersCount[Us] = b ? count_1s_max_15(b) / 2 : EmptyBoardBB; + ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = EmptyBoardBB; + } } @@ -530,7 +525,7 @@ namespace { ei.attackedBy[Us][Piece] |= b; // King attacks - if (b & ei.kingZone[Us]) + if (ei.updateKingTables[Us] && (b & ei.kingZone[Us])) { ei.kingAttackersCount[Us]++; ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; @@ -668,7 +663,7 @@ namespace { // evaluate_king<>() assigns bonuses and penalties to a king of a given color template - Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { + Score evaluate_king(const Position& pos, EvalInfo& ei, Value& margin) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -681,9 +676,8 @@ namespace { // King safety. This is quite complicated, and is almost certainly far // from optimally tuned. - if ( ei.kingAttackersCount[Them] >= 2 - && pos.non_pawn_material(Them) >= QueenValueMidgame + RookValueMidgame - && pos.piece_count(Them, QUEEN) >= 1 + if ( ei.updateKingTables[Them] + && ei.kingAttackersCount[Them] >= 2 && ei.kingAdjacentZoneAttacksCount[Them]) { // Find the attacked squares around the king which has no defenders @@ -717,6 +711,24 @@ namespace { * (Them == pos.side_to_move() ? 2 : 1); } + // Analyse enemy's safe rook contact checks. First find undefended + // squares around the king attacked by enemy rooks... + b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces_of_color(Them); + + // Consider only squares where the enemy rook gives check + b &= RookPseudoAttacks[ksq]; + + if (b) + { + // ...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][QUEEN]); + if (b) + attackUnits += RookContactCheckBonus + * count_1s_max_15(b) + * (Them == pos.side_to_move() ? 2 : 1); + } + // Analyse enemy's safe distance checks for sliders and knights safe = ~(pos.pieces_of_color(Them) | ei.attackedBy[Us][0]); @@ -752,7 +764,8 @@ namespace { // 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. bonus -= KingDangerTable[Us][attackUnits]; - margins[Us] += mg_value(KingDangerTable[Us][attackUnits]); + if (pos.side_to_move() == Us) + margin += mg_value(KingDangerTable[Us][attackUnits]); } return bonus; }