X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fevaluate.cpp;h=ed1d5cb8b08ba7bf37f3632fbc266e7e1fc678b7;hp=f27c04ec834ae4ef3b870b6a56739382b556ad2f;hb=17b71fe51da9d0803c7cfe9fa5df981c4a8fcb8f;hpb=4e5d834e8e25c1120269fe3d0f20220ef2056cb8 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f27c04ec..ed1d5cb8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -36,8 +36,8 @@ namespace { struct EvalInfo { // Pointers to material and pawn hash table entries - MaterialEntry* mi; - PawnEntry* pi; + Material::Entry* mi; + Pawns::Entry* pi; // attackedBy[color][piece type] is a bitboard representing all squares // attacked by a given color and piece type, attackedBy[color][0] contains @@ -75,8 +75,8 @@ namespace { const int GrainSize = 8; // Evaluation weights, initialized from UCI options - enum { Mobility, PassedPawns, Space, KingDangerUs, KingDangerThem }; - Score Weights[6]; + enum { Mobility, PassedPawns, Space }; + Score Weights[3]; typedef Value V; #define S(mg, eg) make_score(mg, eg) @@ -88,7 +88,7 @@ namespace { // // Values modified by Joona Kiiski const Score WeightsInternal[] = { - S(252, 344), S(216, 266), S(46, 0), S(247, 0), S(259, 0) + S(252, 344), S(216, 266), S(46, 0) }; // MobilityBonus[PieceType][attacked] contains mobility bonuses for middle and @@ -150,6 +150,8 @@ namespace { #undef S + Score BishopPinBonus = make_score(15, 25); + // Bonus for having the side to move (modified by Joona Kiiski) const Score Tempo = make_score(24, 11); @@ -195,6 +197,10 @@ namespace { // the strength of the enemy attack are added up into an integer, which // is used as an index to KingDangerTable[]. // + // King safety evaluation is asymmetrical and different for us (root color) + // and for our opponent. These values are used to init KingDangerTable. + const int KingDangerWeights[] = { 259, 247 }; + // KingAttackWeights[PieceType] contains king attack weights by piece type const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 }; @@ -244,7 +250,7 @@ namespace { Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility); template - Score evaluate_king(const Position& pos, EvalInfo& ei, int16_t margins[]); + Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]); template Score evaluate_threats(const Position& pos, EvalInfo& ei); @@ -281,19 +287,16 @@ namespace Eval { void init() { - Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]); - Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]); - Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]); - Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]); - Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]); - - // King safety is asymmetrical. Our king danger level is weighted by - // "Cowardice" UCI parameter, instead the opponent one by "Aggressiveness". - // If running in analysis mode, make sure we use symmetrical king safety. We - // do this by replacing both Weights[kingDangerUs] and Weights[kingDangerThem] - // by their average. + Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]); + Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]); + Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]); + + int KingDanger[] = { KingDangerWeights[0], KingDangerWeights[1] }; + + // If running in analysis mode, make sure we use symmetrical king safety. + // We do so by replacing both KingDanger weights by their average. if (Options["UCI_AnalyseMode"]) - Weights[KingDangerUs] = Weights[KingDangerThem] = (Weights[KingDangerUs] + Weights[KingDangerThem]) / 2; + KingDanger[0] = KingDanger[1] = (KingDanger[0] + KingDanger[1]) / 2; const int MaxSlope = 30; const int Peak = 1280; @@ -302,9 +305,11 @@ namespace Eval { { t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope)); - KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]); - KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]); + KingDangerTable[0][i] = apply_weight(make_score(t, 0), make_score(KingDanger[0], 0)); + KingDangerTable[1][i] = apply_weight(make_score(t, 0), make_score(KingDanger[1], 0)); } + + BishopPinBonus = make_score(Options["pin_open"], Options["pin_end"]); } @@ -361,29 +366,16 @@ namespace { template Value do_evaluate(const Position& pos, Value& margin) { - assert(!pos.in_check()); + assert(!pos.checkers()); EvalInfo ei; + Value margins[COLOR_NB]; Score score, mobilityWhite, mobilityBlack; - - Key key = pos.key(); - Eval::Entry* e = pos.this_thread()->evalTable[key]; - - // If e->key matches the position's hash key, it means that we have analysed - // this node before, and we can simply return the information we found the last - // time instead of recomputing it. - if (e->key == key) - { - margin = Value(e->margins[pos.side_to_move()]); - return e->value; - } - - // Otherwise we overwrite current content with this node info. - e->key = key; + Thread* th = pos.this_thread(); // margins[] store the uncertainty estimation of position's evaluation // that typically is used by the search for pruning decisions. - e->margins[WHITE] = e->margins[BLACK] = VALUE_ZERO; + margins[WHITE] = margins[BLACK] = VALUE_ZERO; // Initialize score by reading the incrementally updated scores included // in the position object (material + piece square tables) and adding @@ -391,7 +383,7 @@ Value do_evaluate(const Position& pos, Value& margin) { score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo); // Probe the material hash table - ei.mi = pos.this_thread()->materialTable.probe(pos); + ei.mi = Material::probe(pos, th->materialTable, th->endgames); score += ei.mi->material_value(); // If we have a specialized evaluation function for the current material @@ -399,12 +391,11 @@ Value do_evaluate(const Position& pos, Value& margin) { if (ei.mi->specialized_eval_exists()) { margin = VALUE_ZERO; - e->value = ei.mi->evaluate(pos); - return e->value; + return ei.mi->evaluate(pos); } // Probe the pawn hash table - ei.pi = pos.this_thread()->pawnTable.probe(pos); + ei.pi = Pawns::probe(pos, th->pawnsTable); score += ei.pi->pawns_value(); // Initialize attack and king safety bitboards @@ -419,8 +410,8 @@ Value do_evaluate(const Position& pos, Value& margin) { // Evaluate kings after all other pieces because we need complete attack // information when computing the king safety evaluation. - score += evaluate_king(pos, ei, e->margins) - - evaluate_king(pos, ei, e->margins); + score += evaluate_king(pos, ei, margins) + - evaluate_king(pos, ei, margins); // Evaluate tactical threats, we need full attack information including king score += evaluate_threats(pos, ei) @@ -466,7 +457,7 @@ Value do_evaluate(const Position& pos, Value& margin) { sf = ScaleFactor(50); } - margin = Value(e->margins[pos.side_to_move()]); + margin = margins[pos.side_to_move()]; Value v = interpolate(score, ei.mi->game_phase(), sf); // In case of tracing add all single evaluation contributions for both white and black @@ -483,8 +474,8 @@ Value do_evaluate(const Position& pos, Value& margin) { Score b = make_score(ei.mi->space_weight() * evaluate_space(pos, ei), 0); trace_add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space])); trace_add(TOTAL, score); - TraceStream << "\nUncertainty margin: White: " << to_cp(Value(e->margins[WHITE])) - << ", Black: " << to_cp(Value(e->margins[BLACK])) + TraceStream << "\nUncertainty margin: White: " << to_cp(margins[WHITE]) + << ", Black: " << to_cp(margins[BLACK]) << "\nScaling: " << std::noshowpos << std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, " << std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * " @@ -492,7 +483,7 @@ Value do_evaluate(const Position& pos, Value& margin) { << "Total evaluation: " << to_cp(v); } - return e->value = pos.side_to_move() == WHITE ? v : -v; + return pos.side_to_move() == WHITE ? v : -v; } @@ -590,22 +581,15 @@ Value do_evaluate(const Position& pos, Value& margin) { mobility += MobilityBonus[Piece][mob]; - // Add a bonus if a slider is pinning an enemy piece - if ( (Piece == BISHOP || Piece == ROOK || Piece == QUEEN) - && (PseudoAttacks[Piece][pos.king_square(Them)] & s)) - { - b = BetweenBB[s][pos.king_square(Them)] & pos.pieces(); - - assert(b); - - if (!more_than_one(b) && (b & pos.pieces(Them))) - score += ThreatBonus[Piece][type_of(pos.piece_on(lsb(b)))]; - } - // Decrease score if we are attacked by an enemy pawn. Remaining part // of threat evaluation must be done later when we have full attack info. if (ei.attackedBy[Them][PAWN] & s) score -= ThreatenedByPawnPenalty[Piece]; + else if (Piece == BISHOP && (PseudoAttacks[Piece][pos.king_square(Them)] & s)) { + const Bitboard between = BetweenBB[s][pos.king_square(Them)] & pos.pieces(); + if (!more_than_one(between)) + score += BishopPinBonus; + } // Bishop and knight outposts squares if ( (Piece == BISHOP || Piece == KNIGHT) @@ -712,8 +696,7 @@ Value do_evaluate(const Position& pos, Value& margin) { & ~ei.attackedBy[Them][0]; if (undefendedMinors) - score += more_than_one(undefendedMinors) ? UndefendedMinorPenalty * 2 - : UndefendedMinorPenalty; + score += UndefendedMinorPenalty; // Enemy pieces not defended by a pawn and under our attack weakEnemies = pos.pieces(Them) @@ -767,7 +750,7 @@ Value do_evaluate(const Position& pos, Value& margin) { // evaluate_king<>() assigns bonuses and penalties to a king of a given color template - Score evaluate_king(const Position& pos, EvalInfo& ei, int16_t margins[]) { + Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -867,7 +850,7 @@ Value do_evaluate(const Position& pos, Value& margin) { // 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. score -= KingDangerTable[Us == Search::RootColor][attackUnits]; - margins[Us] += int16_t(mg_value(KingDangerTable[Us == Search::RootColor][attackUnits])); + margins[Us] += mg_value(KingDangerTable[Us == Search::RootColor][attackUnits]); } if (Trace) @@ -1013,7 +996,7 @@ Value do_evaluate(const Position& pos, Value& margin) { // Opponent king cannot block because path is defended and position // is not in check. So only friendly pieces can be blockers. - assert(!pos.in_check()); + assert(!pos.checkers()); assert((queeningPath & pos.pieces()) == (queeningPath & pos.pieces(c))); // Add moves needed to free the path from friendly pieces and retest condition @@ -1160,7 +1143,11 @@ Value do_evaluate(const Position& pos, Value& margin) { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - return popcount(safe) + popcount(behind & safe); + // Since SpaceMask[Us] is fully on our half of the board + assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0); + + // Count safe + (behind & safe) with a single popcount + return popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe)); }