From 7ea5659c5fe0325f1b6ee5fec06ecd0f066e81c3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?St=C3=A9phane=20Nicolet?= Date: Thu, 15 Oct 2015 21:27:52 -0700 Subject: [PATCH 1/1] Asymmetry bonus for the attacking side Use asymmetry in the position (king separation, pawn structure) to compute an "initiative bonus" for the attacking side. Passed STC: LLR: 2.95 (-2.94,2.94) [0.00,5.00] Total: 14563 W: 2826 L: 2636 D: 9101 And LTC: LLR: 2.96 (-2.94,2.94) [0.00,5.00] Total: 14363 W: 2317 L: 2141 D: 9905 Bench: 8116244 Resolves #462 --- src/evaluate.cpp | 29 ++++++++++++++++++++++++----- src/pawns.cpp | 1 + src/pawns.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0554f490..bbca9964 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -686,6 +686,27 @@ namespace { return make_score(bonus * weight * weight, 0); } + + // evaluate_initiative() computes the initiative correction value for the position, i.e. + // second order bonus/malus based on the known attacking/defending status of the players. + Score evaluate_initiative(const Position& pos, const EvalInfo& ei, const Score positional_score) { + + int pawns = pos.count(WHITE) + pos.count(BLACK); + int king_separation = distance(pos.square(WHITE), pos.square(BLACK)); + int asymmetry = ei.pi->pawn_asymmetry(); + + // Compute the initiative bonus for the attacking side + int attacker_bonus = 8 * (pawns + asymmetry + king_separation) - 120; + + // Now apply the bonus: note that we find the attacking side by extracting the sign + // of the endgame value of "positional_score", and that we carefully cap the bonus so + // that the endgame score with the correction will never be divided by more than two. + int eg = eg_value(positional_score); + int value = ((eg > 0) - (eg < 0)) * std::max( attacker_bonus , -abs( eg / 2 ) ); + + return make_score( 0 , value ) ; + } + } // namespace @@ -767,6 +788,9 @@ Value Eval::evaluate(const Position& pos) { // Evaluate space for both sides, only during opening if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222) score += (evaluate_space(pos, ei) - evaluate_space(pos, ei)) * Weights[Space]; + + // Evaluate initiative + score += evaluate_initiative(pos, ei, score); // Scale winning side if position is more drawish than it appears Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK; @@ -798,11 +822,6 @@ Value Eval::evaluate(const Position& pos) { sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(51) : ScaleFactor(37); } - // Scale endgame by number of pawns - int p = pos.count(WHITE) + pos.count(BLACK); - int v_eg = 1 + abs(int(eg_value(score))); - sf = ScaleFactor(std::max(sf / 2, sf - 8 * SCALE_FACTOR_NORMAL * (12 - p) / v_eg)); - // Interpolate between a middlegame and a (scaled by 'sf') endgame score Value v = mg_value(score) * int(me->game_phase()) + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; diff --git a/src/pawns.cpp b/src/pawns.cpp index 47f74f84..e2fcfc79 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -243,6 +243,7 @@ Entry* probe(const Position& pos) { e->key = key; e->score = evaluate(pos, e) - evaluate(pos, e); + e->asymmetry = popcount( e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK] ); return e; } diff --git a/src/pawns.h b/src/pawns.h index aacaf724..2b978ba0 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -36,6 +36,7 @@ struct Entry { Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard passed_pawns(Color c) const { return passedPawns[c]; } int pawn_span(Color c) const { return pawnSpan[c]; } + int pawn_asymmetry() const { return asymmetry; } int semiopen_file(Color c, File f) const { return semiopenFiles[c] & (1 << f); @@ -71,6 +72,7 @@ struct Entry { int semiopenFiles[COLOR_NB]; int pawnSpan[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] + int asymmetry; }; typedef HashTable Table; -- 2.39.2