Asymmetry bonus for the attacking side
authorSt├ęphane Nicolet <cassio@free.fr>
Fri, 16 Oct 2015 04:27:52 +0000 (21:27 -0700)
committerGary Linscott <glinscott@gmail.com>
Fri, 16 Oct 2015 04:27:52 +0000 (21:27 -0700)
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
src/pawns.cpp
src/pawns.h

index 0554f490227b51e4b60ddacb1cee315bf03c174c..bbca9964f4337d9506c23d0d49353af9f0e2e9d3 100644 (file)
@@ -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<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
+    int king_separation =  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(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<WHITE>(pos, ei) - evaluate_space<BLACK>(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<PAWN>(WHITE) + pos.count<PAWN>(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;
index 47f74f84ee77888d60dacf0e03251977d3cc82ff..e2fcfc79b2f799c7b9b549c5a2af9e688926afa8 100644 (file)
@@ -243,6 +243,7 @@ Entry* probe(const Position& pos) {
 
   e->key = key;
   e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
+  e->asymmetry = popcount<Max15>( e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK] );
   return e;
 }
 
index aacaf7247713616910c5e0b5ddb6e3ac68ba04cd..2b978ba0eec39224cf09565fec20164761c2daa2 100644 (file)
@@ -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<Entry, 16384> Table;