Introduce bad outpost penalty
authorSFisGOD <jonathandumale@gmail.com>
Wed, 8 Jul 2020 02:09:32 +0000 (10:09 +0800)
committerJoost VandeVondele <Joost.VandeVondele@gmail.com>
Sat, 11 Jul 2020 09:23:55 +0000 (11:23 +0200)
In some French games, Stockfish likes to bring the Knight to a bad outpost spot. This is evident in TCEC S18 Superfinal Game 63, where there is a Knight outpost on the queenside but is actually useless. Stockfish is effectively playing a piece down while holding ground against Leela's break on the kingside.

This patch turns the +56 mg bonus for a Knight outpost into a -7 mg penalty if it satisfies the following conditions:

* The outpost square is not on the CenterFiles (i.e. not on files C,D,E and F)
* The knight is not attacking non pawn enemies.
* The side where the outpost is located contains only few enemies, with a particular conditional_more_than_two() implementation

Thank you to apospa...@gmail.com for bringing this to our attention and for providing insights.
See https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/dEXNzSIBgZU
Reference game: https://tcec-chess.com/#div=sf&game=63&season=18

Passed STC:
LLR: 2.93 (-2.94,2.94) {-0.50,1.50}
Total: 6960 W: 1454 L: 1247 D: 4259
Ptnml(0-2): 115, 739, 1610, 856, 160
https://tests.stockfishchess.org/tests/view/5f08221059f6f0353289477e

Passed LTC:
LLR: 2.98 (-2.94,2.94) {0.25,1.75}
Total: 21440 W: 2767 L: 2543 D: 16130
Ptnml(0-2): 122, 1904, 6462, 2092, 140
https://tests.stockfishchess.org/tests/view/5f0838ed59f6f035328947a2

various related tests show strong test results, but so far no generalizations or simplifications of conditional_more_than_two() are found. See PR for details.

closes https://github.com/official-stockfish/Stockfish/pull/2803

Bench: 4366686

src/bitboard.h
src/evaluate.cpp

index afeb40ec146f2af01d2626111fe19450148c90f3..15ec4153362d82d1339e9657e19190cf2e118005 100644 (file)
@@ -130,6 +130,13 @@ constexpr bool more_than_one(Bitboard b) {
   return b & (b - 1);
 }
 
+/// Counts the occupation of the bitboard depending on the occupation of SQ_A1
+/// as in `b & (1ULL << SQ_A1) ? more_than_two(b) : more_than_one(b)`
+
+constexpr bool conditional_more_than_two(Bitboard b) {
+  return b & (b - 1) & (b - 2);
+}
+
 constexpr bool opposite_colors(Square s1, Square s2) {
   return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1;
 }
index 6f2dd69ba33d7a5986fe99be7d70493d29023c76..ca6ea5c44fd6da373d4e1cf9bf10deca66d2771f 100644 (file)
@@ -134,6 +134,7 @@ namespace {
   };
 
   // Assorted bonuses and penalties
+  constexpr Score BadOutpost          = S( -7, 36);
   constexpr Score BishopOnKingRing    = S( 24,  0);
   constexpr Score BishopPawns         = S(  3,  7);
   constexpr Score BishopXRayPawns     = S(  4,  5);
@@ -310,7 +311,13 @@ namespace {
         {
             // Bonus if piece is on an outpost square or can reach one
             bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them);
-            if (bb & s)
+            if (   Pt == KNIGHT
+                && bb & s & ~CenterFiles
+                && !(b & pos.pieces(Them) & ~pos.pieces(PAWN))
+                && !conditional_more_than_two(
+                      pos.pieces(Them) & ~pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide)))
+                score += BadOutpost;
+            else if (bb & s)
                 score += Outpost[Pt == BISHOP];
             else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
                 score += ReachableOutpost;