Rewrite KBBKN endgame
authorMarco Costalba <mcostalba@gmail.com>
Mon, 2 Sep 2013 09:03:01 +0000 (11:03 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 2 Sep 2013 09:03:01 +0000 (11:03 +0200)
This was thought to be a draw but the bishops generally win. However,
it takes up to 66 moves. The position in the diagram was thought to be
a draw for over one hundred years, but tablebases show that White wins
in 45 moves. All of the long wins go through this type of semi-fortress
position. It takes several moves to force Black out of the temporary
fortress in the corner; then precise play with the bishops prevents Black
from forming the temporary fortress in another corner (Nunn 1995:265ff).

Before computer analysis, Speelman listed this position as unresolved,
but "probably a draw" (Speelman 1981:109).

bench: 3453945

src/endgame.cpp

index e45f9ed3fe34ddfb357882ffccddc8f89f75ff76..b78d1ba909f64f19845cc29f7b4d93ea2a64be7a 100644 (file)
@@ -57,7 +57,7 @@ namespace {
 
   // Tables used to drive a piece towards or away from another piece
   const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
-  const int PushAway [8] = { 0, 10, 14, 20, 30, 42, 58, 80 };
+  const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
 
   // Get the material key of a Position out of the given endgame key code
   // like "KBPKN". The trick here is to first forge an ad-hoc fen string
@@ -365,6 +365,11 @@ Value Endgame<KQKR>::operator()(const Position& pos) const {
   return strongerSide == pos.side_to_move() ? result : -result;
 }
 
+
+/// KBB vs KN. This is almost always a win. We try to push enemy king to a corner
+/// and away from his knight. For a reference of this difficult endgame see:
+/// en.wikipedia.org/wiki/Chess_endgame#Effect_of_tablebases_on_endgame_theory
+
 template<>
 Value Endgame<KBBKN>::operator()(const Position& pos) const {
 
@@ -374,14 +379,14 @@ Value Endgame<KBBKN>::operator()(const Position& pos) const {
   assert(pos.count<KNIGHT>(weakerSide  ) == 1);
   assert(!pos.pieces(PAWN));
 
-  Square wksq = pos.king_square(strongerSide);
-  Square bksq = pos.king_square(weakerSide);
-  Square nsq = pos.list<KNIGHT>(weakerSide)[0];
+  Square winnerKSq = pos.king_square(strongerSide);
+  Square loserKSq = pos.king_square(weakerSide);
+  Square knightSq = pos.list<KNIGHT>(weakerSide)[0];
 
-  Value result =  BishopValueEg
-                + PushClose[square_distance(wksq, bksq)]
-                + square_distance(bksq, nsq) * 32
-                + (8 - popcount<Max15>(pos.attacks_from<KNIGHT>(nsq))) * 8;
+  Value result =  VALUE_KNOWN_WIN
+                + PushToCorners[loserKSq]
+                + PushClose[square_distance(winnerKSq, loserKSq)]
+                + PushAway[square_distance(loserKSq, knightSq)];
 
   return strongerSide == pos.side_to_move() ? result : -result;
 }