# What's the rationale behind chess engines conditionally allowing threefold repetitions when assigning a draw score?

When a chess engine sees a position p repeated once (i.e. position p occurred twice) it immediately assigns the second occurrence of position p a draw score. This makes sense because position p doesn't need to occur thrice in order for the chess engine to realize that it's not making progress (i.e. a twofold repetition is just as drawn as a threefold repetition).

Many chess engines do just this. They assign a draw score to all twofold repetitions. However, some of the best chess engines such as Stockfish and Ethereal don't assign a draw score to all twofold repetitions. If the first occurrence of position p is not strictly after the root node then they don't assign a draw score to the twofold repetition. Instead, the position needs to be repeated twice (i.e. it needs to be a threefold repetition) in order for it to be assigned a draw score.

For example, consider the following `drawnByRepetition` function from the Ethereal source code:

``````int drawnByRepetition(Board *board, int height) {

int reps = 0;

// Look through hash histories for our moves
for (int i = board->numMoves - 2; i >= 0; i -= 2) {

// No draw can occur before a zeroing move
if (i < board->numMoves - board->fiftyMoveRule)
break;

// Check for matching hash with a two fold after the root,
// or a three fold which occurs in part before the root move
if (    board->history[i] == board->hash
&& (i > board->numMoves - height || ++reps == 2))
return 1;
}

return 0;
}
``````

As you can see either `i` must be greater than the root node (i.e. it must come after the root node) or the position p needs to be repeated twice (i.e. it must be a threefold repetition) for it to be assigned a draw score.

The chess programming wiki has the following to say about assigning draw score to repetitions:

Threefold repetition implies a position occurred thrice, that is repeated twice. When to score the position as a draw, however, is an entirely different matter. Most programs do this on the first repetition, no matter whether the first occurrence of the repeated position appears in the current search space, or not. Other programs consider that fact, they avoid cycles inside the current search tree to make it a directed acyclic graph (DAG), but allow a one-fold repetition, if the first occurrence appears in the game history before the current root. Anyway, to wait for the second repetition one has its pros and cons. The Repetition score is either zero or the contempt factor.

It says that “to wait for the second repetition one has its pros and cons.” So, what exactly are the pros and cons? I couldn't find an explanation as to why top chess engines like Stockfish and Ethereal do this.

It says that “to wait for the second repetition one has its pros and cons.” So, what exactly are the pros and cons? I couldn't find an explanation as to why top chess engines like Stockfish and Ethereal do this.

My discussion will be technical, so let's make it as simple as possible. Firstly, let's make be clear about this:

If the first occurrence of position p is not strictly after the root node then they don't assign a draw score to the twofold repetition.

Why would an engine do that? Let's consider two scenarios where we have three-fold repetition during the search. Let's assume we are on move 30th, and the engine is thinking at move 40th.

• The position repeated and played on the board, for example, the position occurred on move 24th and 26th.
• The position never actually played on the board, but it is part of the search. The position occurred at move 35th. (IMPORTANT - only a single repetition)

Scenario 1

In the first scenario, it's a repetition that we all understand. In your code example:

``````++reps == 2
``````

So, if a position repeated twice earlier in the game before the root (root == current board position), it's a three-fold repetition. Very simple.

Scenario 2

What about the second scenario? You have the identical position on move 35th, and the same position come back on move 40th. Thus, it's reasonable to assume if you search further you will encounter the position again (for the third repetition). For example, move 45th.

``````i > board->numMoves - height
``````

So, what exactly are the pros and cons?

Pros: search quicker and deeper

Cons: you assume the same position would occur again later in the search (e.g. move 45th), which is not always true

I couldn't find an explanation as to why top chess engines like Stockfish and Ethereal do this.

Search quicker and deeper. Common optimization in modern chess programming.

• Right, but I'm more interested in the case where a position occurs twice, once before the current root (say at move 24) and once after the current root (say at move 40), where the current root is move 30. In this case, we won't assign a draw score because 24 is lesser than 30 and the position has only been repeated once. My question is why would you not want to assign a draw score to the position at move 40 in this case? Commented Oct 14, 2018 at 21:02
• @AaditMShah we would assign a draw score in this case including your code example Commented Oct 15, 2018 at 2:31
• Actually, we wouldn't. It's not a threefold repetition and the first occurrence was before the root node. Thus, we don't assign it a draw score. Hence the question. Commented Oct 15, 2018 at 22:44
• @AaditMShah we would as soon as we see the first repetition after the root Commented Oct 16, 2018 at 1:34
• Actually, because of the order in which we check the positions (i.e. from most recent to least recent) if we don't see a position after the root only then do we check for repetitions. Commented Oct 16, 2018 at 5:20

Looking at some of the forum discussions at the end of the linked chessprogramming.org page, you can see some of the rationale for waiting for the third repetition to consider a position drawn if the first occurrence of the position was before the root.

https://www.stmintz.com/ccc/index.php?id=47672

My program was playing a game against Greg Kennedy a long time ago, and the following situation occurred.

The program was down two pawns and was completely lost. But Kennedy made a mistake, and my program made a move that won a pawn. At this point the best move from Kennedy's point of view was to undo the move he'd just done. My program's move forced him off of something he was defending, and he had to go back to where he was, and now the program could simply take a pawn that was sitting there for free, vastly improve its chances for a draw.

But that's not what it did. The move it made to win the pawn was also retractable, so it chose to repeat the position, and scored this as 0.00.

Of course, rather than repeating his mistake, Kennedy chose a better move and my program was down two pawns again.

I think this one exemplifies the situation best. In the search, the program assumes that both sides will play the position perfectly. However, this is not the case in real life, especially when a human is involved. As such, reaching a certain position in the past may have been a mistake that should be avoided, and the opponent would likely avoid making that same mistake again if given the opportunity. If the search considers a position drawn on the first repetition, irrespective of whether the position was first reached in the actual game history or in the search, it could miss that the position is actually bad for the opponent and that they would avoid the second repetition.

However, if the repeated position first occurs in the search tree, then it should be safe to assume it as drawn on the first repeat. The search assumes perfect play, so if the first occurrence of the position was not a mistake, and repeating it once is also not a mistake, then three times would not be a mistake either. Perfect play would thus continue on and bring us back to the same position ad infinitum were it not for the three-fold repetition rule.

Let's say your engine sees the best moves in a position as +0.08 and +0.06. It plays the +0.08 move and the opponent replies. In the new position, the engine realizes that it was slightly optimistic, and the best continuation is now +0.01 unless it repeats the position. I think it makes more sense for it to evaluate the repetition as +0.06 than a flat 0. It is, after all, not an automatic draw to repeat the position once.

It is, of course, very possible that after the engine repeats and plays the +0.06 move, it will again find that it was optimistic (perhaps for the same general reason) and now the best move is -0.01. Perhaps it now missed its chance to get the +0.01.

So, which scenario is more likely?