Thursday, July 25, 2013

Fifty-move rule

When you ask an average chess player what the 50 move rule in chess is about he will probably say something like
A game is draw if no capture has been made and no pawn has been moved in the last fifty consecutive moves
I would have said the same and so I implemented it in iCE. But actually this is not correct. If you look the rule up in the FIDE laws they state

The game is drawn, upon a correct claim by the player having the move, if
(a) he writes on his scoresheet, and declares to the arbiter his intention to make a move which shall result in the last 50 moves having been made by each player without the movement of any pawn and without the capture of any piece, or
(b) the last 50 consecutive moves have been made by each player without the movement of any pawn and without the capture of any piece.
Of course it is difficult for a UCI chess engine to write on a scoresheet or even to claim a draw. This is usually done by the GUI automatically. But one important point remains. The game is not automatically a draw after 50 moves, there must exist a side having the right to move.

Why is that important ?

If one side mates the opponent with its 50th move the result is mate and not draw because after a mate there is no side to move that can claim a draw anymore.

Well, how likely is this having any relevance?

It is not as unlikely as one might think. The difference will be suppressed because often games are adjudicated very early by the GUI to save time. But if games are played until the end it will show up sooner or later.

One tester of iCE made me aware of a game where iCE just gave away half a point.

6R1/8/8/8/4K3/4N3/4r2k/8 b - - 96 147
Already 48 moves (96 plies) have been played. The draw is in sight. But what did iCE as Black play?

147.  ..  Kh3??
148. Kf3  Rh2
149. Rh8#

iCE was just assuming that Rh8 will finish the 50 move sequence and draw so he walked into the mate. An analyses shows this clearly. It sees Kh3 as a drawing move.

position fen 6R1/8/8/8/4K3/4N3/4r2k/8 b - - 96 147
analyze depth 8
e2e3 : -32.463  e2e3 e4e3
e2a2 :       0  e2a2 e3f5 a2a1 f5g7
e2e1 :       0  e2e1 g8h8 h2g3 h8g8
h2h3 :       0  h2h3 g8h8 h3g3 h8g8
e2g2 : -32.461  e2g2 g8g2 h2h1 g2c2 h1g1 e4f3 g1h1 c2c1 h1h2 e3g4 h2h3 c1h1
e2f2 :  -1.372  e2f2 e3g4 h2h3 g4f2 h3h2
e2d2 :  -1.346  e2d2 e3f1 h2h3 f1d2 h3h4 e4f4 h4h5 g8g5 h5h4 d2e4
e2c2 :  -1.373  e2c2 e3c2 h2h3 c2d4 h3h4 e4e5 h4h5 d4f5
e2b2 :       0  e2b2 e3f1 h2h3 g8h8
h2h1 :       0  h2h1 g8h8 e2h2 h8h2 h1h2


After knowing there is a problem it was easy to fix. I only had to remove a single character in the source.

inline bool TBoardStateHistory::is50MoveDraw()
{
    return hmc > 100;    // was hmc >= 100
}


Now it solves the above position correctly

position fen 6R1/8/8/8/4K3/4N3/4r2k/8 b - - 96 147
analyze depth 6
e2e3 : -32.463  e2e3 e4e3
e2a2 :       0  e2a2 e3f5 h2h3 f5g7
e2e1 :       0  e2e1 g8h8 h2g3 h8f8 e1h1
h2h3 :  -1.345  h2h3 e4f3 h3h4 f3e2 h4h5 e3f5
e2g2 :  -1.401  e2g2 g8g2 h2h1 g2f2 h1g1 f2f1 g1h2 e3d5
e2f2 :  -1.181  e2f2 e3g4 h2g2 g4f2 g2f1 g8h8 f1g1
e2d2 :  -1.378  e2d2 e3f1 h2h3 f1d2 h3h4 d2f3 h4h5 f3e5
e2c2 :  -1.378  e2c2 e3c2 h2h3 c2d4 h3h4 d4f3 h4h5 f3e5
e2b2 :       0  e2b2 e3f1 h2h3 e4f5 h3h4
h2h1 :       0  h2h1 g8h8 e2h2 h8g8 h2g2


It sees now that h2h3 will lose the rook to avoid an instant mate and select a different move.

Thanks to jack who reported the issue.