From 9ff594c3a9e3517eb12f0abfced6baa2ac58e4c1 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 2 Sep 2013 11:03:01 +0200 Subject: [PATCH] Rewrite KBBKN endgame 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 | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index e45f9ed3..b78d1ba9 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -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::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::operator()(const Position& pos) const { @@ -374,14 +379,14 @@ Value Endgame::operator()(const Position& pos) const { assert(pos.count(weakerSide ) == 1); assert(!pos.pieces(PAWN)); - Square wksq = pos.king_square(strongerSide); - Square bksq = pos.king_square(weakerSide); - Square nsq = pos.list(weakerSide)[0]; + Square winnerKSq = pos.king_square(strongerSide); + Square loserKSq = pos.king_square(weakerSide); + Square knightSq = pos.list(weakerSide)[0]; - Value result = BishopValueEg - + PushClose[square_distance(wksq, bksq)] - + square_distance(bksq, nsq) * 32 - + (8 - popcount(pos.attacks_from(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; } -- 2.39.2