Two fold or three fold repetition?

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Two fold or three fold repetition?

Post by Sven »

Where do you call that code? When making a move? If so, then why do you allocate a ZobristKey? I would expect that you simply add the already existing hash key of the current board to your "positionHistory" (which appears to be the container that is used for repetition detection).
Sven Schüle (engine author: Jumbo, KnockOut, Surprise)
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

I changed it yesterday. It now allocates a key in Game class. But also in ABSearch.Init. I think not necessary in ABSearch.Init.
So I have to fix that too.

I don't know how to get a key without allocating or maybe create it in on the stack with a struct or something. Even don't know what I am talking about. What is wrong with allocating (on the heap). Is passing it on a stack much better?

By the way evaluation in my chess engine not great. So might be more important to fix.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

Sven wrote: Wed Sep 01, 2021 7:59 am Where do you call that code? When making a move? If so, then why do you allocate a ZobristKey? I would expect that you simply add the already existing hash key of the current board to your "positionHistory" (which appears to be the container that is used for repetition detection).
Yes when making a move in Game class. I also have a class GamePlayer calling make a move. I don't know what it is for. Some old decisions. Maybe I should write a chart to find out what is going on in these classes that call ABSearch. Better not create too small classes. For you get lost by these references. Getting too complicated or at least annoying.

O wait I need two ''gameplayers" to play a game. Both have or use a separate timeControl.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Two fold or three fold repetition?

Post by Sven »

Henk wrote: Wed Sep 01, 2021 10:35 am I don't know how to get a key without allocating or maybe create it in on the stack with a struct or something.
A hash key is usually a 64-bit number. Just a number, nothing you should have to allocate separately. In my view it is one of several board properties, like the bitboards representing the position of pieces on the board, the color that is to move, the ep target square, or the castling rights. It is certainly derived from the other properties I enumerated but I would keep it along with the other attributes since you do not want to recalculate it each time you want to access the hash key of the current position. At the time you calculate it, or do the incremental update, you either deal with a local 64-bit integer variable (in C# of type "ulong") or directly with the data member of the board object.

For repetition detection you also store all hash keys of the whole game up to the current position in some container. The container implementation itself should care about allocation of memory for the data it stores so there should be no reason to allocate single 64-bit numbers when storing them in a container. I would either choose a container of fixed (limited) size or (if you want to support chess games of unlimited length or search trees of unlimited depth) at least a container that resizes itself in a way that does not hurt (i.e., no resizing/shrinking on each single insert/delete operation).
Sven Schüle (engine author: Jumbo, KnockOut, Surprise)
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

Still not fixed. Previous bug was in PVS. PVS modifies historyFromRoot with every move. In end game null move pruning disabled. So should be easier to debug. If I can reproduce it.

[pgn]
[Event "Computer Chess Game"]
[Site "LAPTOP-1FK7MTIP"]
[Date "2021.09.03"]
[Round "5"]
[White "Skipper_8_19"]
[Black "Skipper_8_18"]
[Result "1/2-1/2"]
[TimeControl "60"]
[Annotator "1. +0.50 1... -0.76"]

1. d4 {+0.50/7} d5 {-0.76/9 1.0} 2. Nc3 {-0.04/7 1.0} Bf5 {-0.30/8 1.0} 3.
Nf3 {+0.00/7 1.0} Nf6 {-0.19/8 1.0} 4. e3 {+0.07/6 1.0} Nc6 {-0.57/8 1.0}
5. Bd2 {+0.70/6 0.9} Ne4 {-0.46/7 1.0} 6. Bd3 {+0.22/7 0.9} e6
{-0.09/8 0.9} 7. g4 {+0.16/7 0.9} Nxc3 {+0.07/8 0.9} 8. bxc3 {-0.19/7 0.9}
Bxg4 {-0.29/9 0.9} 9. Rg1 {+0.44/6 0.9} h5 {+0.41/8 0.9} 10. e4
{-0.39/6 0.9} dxe4 {+0.62/8 0.9} 11. Bxe4 {-0.62/6 0.8} f5 {+1.04/8 0.9}
12. Bxc6+ {-0.70/6 0.8} bxc6 {+1.02/9 0.9} 13. h3 {-1.42/7 0.8} Bxh3
{+1.38/8 0.8} 14. Qe2 {-1.93/6 0.8} h4 {+1.92/7 0.8} 15. Ng5 {+0.27/6 0.8}
Qd7 {-0.39/8 0.8} 16. Nxh3 {+0.22/7 0.8} Ba3 {-0.38/7 0.8} 17. Nf4
{+0.22/5 0.8} h3 {-0.29/8 0.8} 18. Qxe6+ {+0.08/6 0.8} Qxe6+ {-0.32/9 0.8}
19. Nxe6 {+0.34/8 0.8} h2 {+0.41/9 0.8} 20. Rh1 {-0.47/7 0.8} Kd7
{-0.06/9 0.8} 21. Nc5+ {+0.26/7 0.8} Bxc5 {-0.38/9 0.7} 22. dxc5
{+0.52/7 0.7} Rae8+ {-0.03/9 0.7} 23. Be3 {+0.07/7 0.7} Kc8 {+0.02/8 0.7}
24. O-O-O {+0.00/7 0.7} Rh3 {-0.72/8 0.7} 25. Rd2 {+0.97/7 0.7} Reh8
{-0.77/8 0.7} 26. f3 {+1.70/8 0.7} a5 {-1.67/8 0.7} 27. Bf4 {+1.51/7 0.7}
Rxf3 {-1.64/9 0.7} 28. Be5 {+1.22/8 0.7} Re3 {-1.40/9 0.7} 29. Bd4
{+1.78/8 0.7} Reh3 {-1.59/9 0.6} 30. Bxg7 {+1.95/8 0.7} R8h7 {-2.92/9 0.7}
31. Be5 {+3.18/8 0.6} Re3 {-3.21/9 0.6} 32. Bd4 {+3.30/8 0.6} Reh3
{-3.24/10 0.6} 33. Kb2 {+3.30/7 0.6} f4 {-3.22/9 0.6} 34. Be5 {+3.12/7 0.6}
R7h4 {-3.15/8 0.6} 35. Rf2 {+3.27/7 0.6} Rh5 {-3.28/9 0.6} 36. Bxf4
{+3.41/8 0.6} Rxc5 {-3.37/9 0.6} 37. Rfxh2 {+3.38/7 0.6} Rb5+ {-3.49/9 0.6}
38. Kc1 {+3.84/8 0.6} Rxc3 {-4.06/9 0.6} 39. Rh8+ {+4.20/7 0.6} Kb7
{-4.07/9 0.6} 40. R1h7 {+4.04/7 0.6} Rbc5 {-3.82/8 0.6} 41. Rxc7+
{+3.98/8 0.5} Kb6 {-3.97/9 0.5} 42. Rb8+ {+4.26/8 0.5} Ka6 {-4.31/9 0.5}
43. Kb1 {+4.33/7 0.5} R5c4 {-4.29/9 0.5} 44. Bd2 {+4.38/7 0.5} Rxc2
{-4.32/9 0.5} 45. Be3 {+4.46/8 0.5} Rc5 {-5.04/10 0.5} 46. Bxc5
{+5.05/7 0.5} Rxc5 {-4.98/10 0.5} 47. Kb2 {+4.62/6 0.5} Rb5+ {-4.39/11 0.5}
48. Rxb5 {+4.27/8 0.5} cxb5 {-4.39/9 0.5} 49. Kb3 {+4.48/7 0.5} Kb6
{-4.43/10 0.5} 50. Rh7 {+4.46/7 0.5} Kc5 {-4.43/8 0.5} 51. a4 {+5.81/8 0.5}
bxa4+ {-5.85/11 0.5} 52. Kxa4 {+5.83/8 0.5} Kd4 {-5.85/10 0.5} 53. Kxa5
{+5.85/7 0.5} Ke3 {-5.83/9 0.4} 54. Kb4 {+5.84/7 0.4} Kf4 {-5.83/9 0.4} 55.
Kc3 {+5.85/8 0.4} Ke5 {-5.84/9 0.4} 56. Kc4 {+5.84/7 0.4} Kd6 {-5.84/9 0.4}
57. Rh6+ {+5.84/8 0.4} Ke5 {-5.86/10 0.4} 58. Kd3 {+5.84/8 0.4} Kf4
{-5.84/9 0.4} 59. Rh5 {+5.87/8 0.4} Kg4 {-5.85/10 0.4} 60. Rb5
{+5.89/8 0.4} Kf4 {-5.85/10 0.4} 61. Rh5 {+5.89/8 0.4} Kf3 {-5.86/11 0.4}
62. Rg5 {+5.90/8 0.4} Kf2 {-5.87/9 0.4} 63. Rd5 {+5.90/8 0.4} Kf3
{-5.87/10 0.4} 64. Rg5 {+5.90/9 0.4} Kf2 {-5.87/10 0.4} 65. Ke4
{+5.92/9 0.4} Ke2 {-5.90/10 0.4} 66. Rh5 {+5.90/8 0.4} Kd2 {-5.90/10 0.4}
67. Rc5 {+5.91/8 0.4} Ke2 {-5.93/11 0.3} 68. Rh5 {+5.91/8 0.4} Kd2
{-5.90/10 0.3} 69. Rc5 {+5.91/8 0.3} Ke2 {-5.93/11 0.3} 70. Rd5
{+5.90/7 0.3} Kf2 {-5.90/10 0.3} 71. Rc5 {+5.91/8 0.3} Ke2 {+0.00/19 0.3}
{XBoard adjudication: repetition draw} 1/2-1/2
[/pgn]
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

The reason why it could not finish the game was because it added random noise to pieceSquareValues. But to reproduce bug you don't want random noise otherwise it will play different moves. Bad example.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

If 64 bits ZobristKey collides when looking up position in a position history/game history/history from root it will give wrong score. Thinking it is a three fold while it isn't. Same holds when using transposition table but then you have an extra check that is to test if move stored in transposition table is valid.

But using a longer key too expensive I think.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Two fold or three fold repetition?

Post by Henk »

I think some move values in TT are corrupt for it allows opponent to make a draw by repetition.
Maybe they were stored when history to root was small and an opponent move did not cause a repetition draw.
But when TT is consulted when history to root is larger an opponent move in the current position may cause a repetion draw when move of TT is played.

So problem is that history to root is not indentical. So position is not identical. So can't trust move plus value from TT for history was different.

Maybe a solution is to store value in TT only if history to root is large enough to detect a repetition draw. But how large 2 or 3 plies?
Or maybe never do transposition table pruning. You only have one move which you can validate but you don't know the best opponent move.
Or maybe research best opponent move ??
Maybe research best move from TT. But never do transposition pruning is less code. Have to find out what is best.