8 . . ♜ . . . ♚ .
7 ♖ . . . . . . .
6 . . . . . . . .
5 . ♖ . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 ♙ . . . . ♔ ♙ ♙
1 . . . . . . . .
a b c d e f g h
Side: white
Enpassant: no
Castling: ----
Hash key: b237bb9812e3bda
info score cp 890 depth 1 nodes 43 time -1328225343 pv b5b7
info score cp 900 depth 2 nodes 216 time -1328225342 pv b5g5 g8f8 g5g7
repetition dedected!
repetition dedected!
repetition dedected!
repetition dedected!
info score cp 890 depth 3 nodes 642 time -1328225341 pv b5g5 g8f8 g5f5 f8g8 f5f7
But if I return 0 when repetition is found for some reason I'm getting the same score
and the number of traversed nodes increases and PV is still the same:
fist of all, you detect a repetition down the tree, so the search may pick another path if it's better
also, you should check for the repetition of a position, not when a single piece repeats a move (because the position may still differ)
Last edited by mar on Mon Sep 21, 2020 5:19 pm, edited 1 time in total.
8 . . ♜ . . . ♚ .
7 ♖ . . . . . . .
6 . . . . . . . .
5 . ♖ . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 ♙ . . . . ♔ ♙ ♙
1 . . . . . . . .
a b c d e f g h
Side: white
Enpassant: no
Castling: ----
Hash key: b237bb9812e3bda
info score cp 890 depth 1 nodes 43 time -1328225343 pv b5b7
info score cp 900 depth 2 nodes 216 time -1328225342 pv b5g5 g8f8 g5g7
repetition dedected!
repetition dedected!
repetition dedected!
repetition dedected!
info score cp 890 depth 3 nodes 642 time -1328225341 pv b5g5 g8f8 g5f5 f8g8 f5f7
But if I return 0 when repetition is found for some reason I'm getting the same score
and the number of traversed nodes increases and PV is still the same:
int negamax(int alpha, int beta, int depth)
{
if (ply && is_repetition())
return 0; // printf("repetition detected!\n")
// read hash entry
if (read_hash_entry(...))
// return hash score...
}
What am I doing wrong?
Should score get changed to 0 instead of 890?
Should PV change?
Well, if i understand the position correctily white is Rook and 3 pawns up, and black has no way of forcing them to repeat position, so
score should not get changed (because 3-fold branches either be prunned or never be chosen).
You should use different test position if you want you engine to change eval and PV.
You can try finding some puzzles, where 3-fold is forced after some sacrifice by losing side, at least in my case
use of such positions did a great help with debugging
8 . . ♜ . . . ♚ .
7 ♖ . . . . . . .
6 . . . . . . . .
5 . ♖ . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 ♙ . . . . ♔ ♙ ♙
1 . . . . . . . .
a b c d e f g h
Side: white
Enpassant: no
Castling: ----
Hash key: b237bb9812e3bda
info score cp 890 depth 1 nodes 43 time -1328225343 pv b5b7
info score cp 900 depth 2 nodes 216 time -1328225342 pv b5g5 g8f8 g5g7
repetition dedected!
repetition dedected!
repetition dedected!
repetition dedected!
info score cp 890 depth 3 nodes 642 time -1328225341 pv b5g5 g8f8 g5f5 f8g8 f5f7
But if I return 0 when repetition is found for some reason I'm getting the same score
and the number of traversed nodes increases and PV is still the same:
int negamax(int alpha, int beta, int depth)
{
if (ply && is_repetition())
return 0; // printf("repetition detected!\n")
// read hash entry
if (read_hash_entry(...))
// return hash score...
}
What am I doing wrong?
Should score get changed to 0 instead of 890?
Should PV change?
I don’t know what your ply is or how your repetition code looks like, but it seems right that you will find some repetitions after four half moves. That you will get the same score seems also be right since the repetition lines will not become the PV and hence not propagate the score.
8 . . ♜ . . . ♚ .
7 ♖ . . . . . . .
6 . . . . . . . .
5 . ♖ . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 ♙ . . . . ♔ ♙ ♙
1 . . . . . . . .
a b c d e f g h
Side: white
Enpassant: no
Castling: ----
Hash key: b237bb9812e3bda
info score cp 890 depth 1 nodes 43 time -1328225343 pv b5b7
info score cp 900 depth 2 nodes 216 time -1328225342 pv b5g5 g8f8 g5g7
repetition dedected!
repetition dedected!
repetition dedected!
repetition dedected!
info score cp 890 depth 3 nodes 642 time -1328225341 pv b5g5 g8f8 g5f5 f8g8 f5f7
But if I return 0 when repetition is found for some reason I'm getting the same score
and the number of traversed nodes increases and PV is still the same:
int negamax(int alpha, int beta, int depth)
{
if (ply && is_repetition())
return 0; // printf("repetition detected!\n")
// read hash entry
if (read_hash_entry(...))
// return hash score...
}
What am I doing wrong?
Should score get changed to 0 instead of 890?
Should PV change?
Well, if i understand the position correctily white is Rook and 3 pawns up, and black has no way of forcing them to repeat position, so
score should not get changed (because 3-fold branches either be prunned or never be chosen).
You should use different test position if you want you engine to change eval and PV.
You can try finding some puzzles, where 3-fold is forced after some sacrifice by losing side, at least in my case
use of such positions did a great help with debugging
Could you please give me a link to 3 fold repetition positions?
Many A/B engines look for 3 reps at the root and score only 2 reps in the search tree as a draw.
FWIW:
I tend to think of 3 reps (and rule 50 moves) as more of a search issue, and not something in the eval (which typically has no knowledge of the prior positions). This is like the in-check search depth extension, so I don't score being in check in the eval either.
Most eval calls are in q-search, and there typically only quiet positions (no good captures per SEE, no promotion, etc) are the ones evaluated. The exceptions are at the extreme maximum depth limit (which can happen in late endgames, although less often with tablebases), and during eval window type pruning in the search.
I went around and around with 3 reps using various test positions. Some would work and then others would not.
In the end, suggest using whatever gains you the most Elo against a mix of comparable opponents (not just self-play).
Of course, how you then handle draws is another area entirely.
PS: As usual, the Crafty source code has lots of well-commented (well-commented to me) code to study for ideas.
brianr wrote: ↑Mon Sep 21, 2020 8:10 pm
3 rep scoring can be quite tricky.
Many A/B engines look for 3 reps at the root and score only 2 reps in the search tree as a draw.
FWIW:
I tend to think of 3 reps (and rule 50 moves) as more of a search issue, and not something in the eval (which typically has no knowledge of the prior positions). This is like the in-check search depth extension, so I don't score being in check in the eval either.
Most eval calls are in q-search, and there typically only quiet positions (no good captures per SEE, no promotion, etc) are the ones evaluated. The exceptions are at the extreme maximum depth limit (which can happen in late endgames, although less often with tablebases), and during eval window type pruning in the search.
I went around and around with 3 reps using various test positions. Some would work and then others would not.
In the end, suggest using whatever gains you the most Elo against a mix of comparable opponents (not just self-play).
Of course, how you then handle draws is another area entirely.
PS: As usual, the Crafty source code has lots of well-commented (well-commented to me) code to study for ideas.
Some time back, when I was going to town on PERFT EPDs trying to find (and make) ones that tested everything, I always intended to make some EPDs that stress tested draw code in search (draws are terminal so they remove PERFT nodes obviously), but never got round to it.
This is probably the easiest position I have. Your engine should avoid Qxa6 and Rxa6 as they both lead to an immediate 3-fold draw:
[d]3r3N/R1p1kppp/n6n/8/2QPP3/5q2/5P1P/5RK1 w - - 0 24
Also, this is a classic position, but it is much harder for young engines to find:
[d]1k6/4R3/1p6/p1p3p1/qnBn2Qp/5P2/1P6/1K6 w - - 0 46
Bb3! eventually leads to draw either by repetition or stalemate