Was watching a game that resulted in this position and my engine played Re7+? Obviously if it had specific knowledge about KKP endgames (or endgame tablebase support) it would have seen this leads to a draw.
I'm curious if anyone has an engine that sees the folly of Re7 very quickly *without* endgame tablebase or special KKP handling. And if so what technique do you use? I have logic to see runaway passers in K vs P endgames, but no logic to recognize blocked passers in K vs P endgames.
My engine takes about 40 seconds and 19 plies to see a correc solution.
When I switch on KingSlayer/Simple's (rather rudimentary) end-game knowledge (the 'drawish material' and 'specific endings' options, KPK being one of the latter), it sees the trouble at 12 ply/0.18 sec (2.4GHz i3):
if(edge) { // rook-pawns: detect some cases that don't apply to other Pawns
int dPath = (hisKing^pawn) & 7; // distance of bare King to Pawn path
if(dPath < 2 && dist[hisKing - promo] < d - dPath) return 1; // bare King in or next to path of Pawn
if(((king^pawn) & 7) == 0 && dist[hisKing - (king^2)] < 2 - myTurn) // own King is trapped in path of Pawn
return 1;
}
But does it really see at this depth that Re7 is a draw, or is it just accidental that it thinks another move is better than an also very positive score? Can you do multi-PV, so that we can see the score of Re7 also at larger depth?
hgm wrote:But does it really see at this depth that Re7 is a draw, or is it just accidental that it thinks another move is better than an also very positive score? Can you do multi-PV, so that we can see the score of Re7 also at larger depth?
You have reason. If I put the position after Re7+, it requires some time until it realizes that is draw, at depth 17:
With it turned off Nemeton struggles as well but in this position it's about edge pawns and edge pawns are even easier to handle than general kpk opposition in the middle of the board.
If you don't have king inside the square of the pawn code you can probably return a draw if the king can reach the g8, h8 and h7 squares.
But I recently added general kpk opposition as well. That always seemed a daunting task to me having to be clever, take in account side to move etc. but nope. Even something so simple as the defending king reaching the two rows infront of the pawn and the attacking king on the same row or behind the pawn handles it well in practise not even looking at side to move or distances to the pawn horizontally. The problem with taking horizontal distances into account infact was that search has a knack of breaking that on the last ply. Stepping it's own king out or forcing the other king out of the draw rule on the last ply. Sneaky sneaky search.
What seemed to be important is that when you are in a position that is recognized as a draw, the defending side should always be able to stay in such a recognized positions. (Of course he will always be able to stay in a position that is a draw, otherwise the current position would not have been a draw in the first place, but it might not be recognized.) Otherwise the search starts stalling to shif the recognized draw position one ply before the horizon, imagining a zugzwang that would revive the win.
int
KPKdraw (int side)
{ // identify some draw positions that will not quickly resolve.
int king = location[side+KING], pawn = location[side+PAWN], hisKing = location[KING+xside];
int myTurn = (side == stm), forward = 16-4*side; // from strong-side POV
int promo = (pawn & 7) + 7*16*!side; // promotion square
int lastRank = !((hisKing^promo) & 0x70); // bare King is on last rank
int next = (king == pawn+1 || king == pawn-1); // strong-side King standing beside Pawn
int edge = (pawn & 7) == 0 || (pawn & 7) == 7; // Pawn is on edge file
int d = dist[pawn-promo], stopSqr;
if(board[pawn] != side+PAWN) return 0; // sanity check, as location[] is not 100% reliable for Pawns
if(dist[hisKing-king] < 2) return 0; // reject illegal position. (KPKdraw is called before legality test...)
if(myTurn && aligned[hisKing-pawn] & code[side+PAWN]) return 0; // Pawn captures King
// rule of squares
d -= (d ==6); // account for initial double-push
if(d - myTurn < dist[hisKing-promo] - 1) return 0; // outside 'square' is always won
if(edge) { // rook-pawns: detect some cases that don't apply to other Pawns
int dPath = (hisKing^pawn) & 7; // distance of bare King to Pawn path
if(dPath < 2 && dist[hisKing - promo] < d - dPath) return 1; // bare King in or next to path of Pawn
if(((king^pawn) & 7) == 0 && dist[hisKing - (king^2)] < 2 - myTurn) // own King is trapped in path of Pawn
return 1;
}
if(hisKing == pawn + forward) return (!lastRank | myTurn); // I must stalemate him or abandon Pawn
if(pawn == (promo^16)) return 0; // play out other 7th-rank Pawns
stopSqr = pawn + 2*forward;
if(stopSqr == promo) { // last-rank defense; quite tricky!
return (dist[hisKing - promo] < 2 && (!next || dist[king + 2*forward - hisKing] + myTurn == 1));
} else return (dist[stopSqr - king] - myTurn > dist[stopSqr - hisKing]);
if(hisKing == stopSqr) return (edge | !lastRank | !myTurn | !next); // 2 squares in front of Pawn
if((pawn&0x70) == (king&0x70)) { // attacking K is on same rank as P
if(dist[stopSqr - hisKing] <= 1 && !myTurn && !lastRank) return 1; // he can step in path
if(hisKing == king + 2*forward) return (!lastRank || next && myTurn); // oppose K next to P (cut off on last rank!)
if(dist[king + 4*forward - hisKing] + myTurn == 1) return 1; // he has far opposition (or can take it)
}
if((pawn&0x70) == (king&0x70) - forward) { // attacking K is on rank before P
return (!lastRank & dist[king + 2*forward - hisKing] + myTurn == 1); // he has opposition, or can take it
}
return 0;
}
This is a bit more complex than I had hoped for, so I wonder if further simplification would be possible.
In practice it is not necessary to solve all positions. You only need to recognize some tedious draws that can be quickly reached. E.g. a lot of positions are draws because the Pawn will be lost. But the search will find those quickly. (OTOH, they also are not difficult to recognize, with the aid of a distance table.) What the search needs help with is 'stand-off' positions, where it is a draw, but you can drag it out almost indefinitely by aimlessly moving around in the draw sector. E.g. in KBPK, where the leading side can keep the material advantage hundreds of moves without repeating by touring the board with its King, and then stepping the Bishop to another square on the diagonal of the Pawn to make another King toer, etc. Those draws the search would never find. Recognizing positions with the defending King on or next to the promotion corner square as draws solves that. That many other positions are draw because you cannot stop the defending King from getting to that corner doesn't contibute much strength, as the search will quickly find that.
In KPK the key positions are those where the defending King is in or next to the path of the Pawn.