Make engine stop repeating moves in a clearly won position

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Make engine stop repeating moves in a clearly won position

Post by mvanthoor »

This irks me to no end. My engine throws games away in a completely won position, like this one:

[d]8/r1r3pk/1N2pp2/3p4/P2QP1qp/1R6/2PB2P1/5RK1 w - - 8 41

My engine (white) is two PIECES up against one pawn, and it insists on repeating Rf1-f4, Qg4-d1, Rf4-f1, Qd1-g4, and so on, until a three-fold repetition occurs, even though the engine can detect position repetition now and scores them with 0.

What is the normal way to make an engine NOT repeat a position if it is up this much material; is it something like: "If repetition detected and up a lot of material, then return minus infinity" or something, to make it see that a repetition in this case will be VERY bad?

Note: Because it only has material and PSQT, my engine scores this position at +5.30. Stockfish scores it at +15.xx for white.

If I could stop the engine drawing games with repetitions in positions like this, it would mean an instant rating increase of a few hundred Elo. Now, it habitually scores around 75% against engines in the 1450 range. That would put it at around +/- 200 Elo above. I think, if I can fix this, Rustic would score at least 90%+ or more, because against 1450 engines, it doesn't lose, except by great exception. It only draws because it can't / won't avoid the repetition.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
tmokonen
Posts: 1296
Joined: Sun Mar 12, 2006 6:46 pm
Location: Kelowna
Full name: Tony Mokonen

Re: Make engine stop repeating moves in a clearly won position

Post by tmokonen »

I think it will work better if you check for 50 move/repetition draws before checking to see if you have reached a depth of 0. Otherwise you might be returning a standpat value rather than a proper draw score.
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Make engine stop repeating moves in a clearly won position

Post by mar »

the solution is simple: just score the repetition as draw. all you have to do is look up the history (since the last irreversible move) to check for reps.
of course you want to do this inside search, at the beginning of each node.
here you should handle draws by repetition, 50 move rule draw (be careful though to score the draw properly here, if you are one ply off, terrible things may happen) and of course draws by insufficient material.
Martin Sedlak
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Make engine stop repeating moves in a clearly won position

Post by mvanthoor »

mar wrote: Tue Oct 27, 2020 9:32 pm the solution is simple: just score the repetition as draw. all you have to do is look up the history (since the last irreversible move) to check for reps.
of course you want to do this inside search, at the beginning of each node.
here you should handle draws by repetition, 50 move rule draw (be careful though to score the draw properly here, if you are one ply off, terrible things may happen) and of course draws by insufficient material.
I already do this. (To make sure I'll test the function again to see if it works properly... but as far as I know, it does.)

It could be this, however:
tmokonen wrote: Tue Oct 27, 2020 9:31 pm I think it will work better if you check for 50 move/repetition draws before checking to see if you have reached a depth of 0. Otherwise you might be returning a standpat value rather than a proper draw score.
I do check for repetitions right AFTER the escape condition "if depth == 0", so it could indeed be that a move repeats the position, but because it's a leaf node it does QSearch and returns the stand-pat score. I'll have to try this. edit: this doesn't work. If I put the check before depth = 0, the a/b-function obviously returns immediately without even running once, so no best move is set.

So I must have some mistake in determining the repetition. I'll remove the calculation and run through the entire list, and have the engine check this position again.
Last edited by mvanthoor on Tue Oct 27, 2020 9:52 pm, edited 1 time in total.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Make engine stop repeating moves in a clearly won position

Post by mar »

mvanthoor wrote: Tue Oct 27, 2020 9:40 pm I already do this. (To make sure I'll test the function again to see if it works properly... but as far as I know, it does.)

I do check for repetitions right AFTER the escape condition "if depth == 0", so it could indeed be that a move repeats the position, but because it's a leaf node it does QSearch and returns the stand-pat score. I'll have to try this.
well, why not do this inside qsearch? like I said, at the beginning of each node (including qs nodes) should do. however, even interior nodes should detect the repetition in the position you posted, so perhaps you have a bug somewhere?
what score does your engine report in the above position?

also: are you sure it detects repetition in the game history before root move as well? (since last irreversible move)?
Martin Sedlak
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Make engine stop repeating moves in a clearly won position

Post by mvanthoor »

The engine only has material counting and PSQT. It reports a score of +5.30.

If I remove the calculation I had in is_repetition() and just run through the entire list, it just reports 0 without making a move if I call this function in alpha/beta. I'll set up the position using the FEN instead of the game, make a repetition and then try again.

Edit: I removed the calculation, and even when I just set up an FEN and try to repeat the position, the engine immediately comes up with a different move where it previously would have made the repetition.

is_repetition is trivial:

Code: Select all

    pub fn is_repetition(board: &Board) -> bool {
        let mut found = false;
        let mut i = 0;

        // If the half-move clock is 10, the position cannot have been
        // repeated in the last 10 moves. Therefore, don't search for
        // repetitions beyond that point.
        let max = board.history.len();

        while i < max && !found {
            let historic = board.history.get_ref(i);
            found = historic.zobrist_key == board.game_state.zobrist_key;
            i += 1;
        }
        found
    }
The only change I made was that "max" before was:

Code: Select all

let max = board.history.len() - board.game_state.half_move_clock;
This line should make the function only search from the first move to where the 50 move rule counter was reset.
Last edited by mvanthoor on Tue Oct 27, 2020 10:06 pm, edited 1 time in total.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Ras
Posts: 2488
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Make engine stop repeating moves in a clearly won position

Post by Ras »

mar wrote: Tue Oct 27, 2020 9:32 pm50 move rule draw (be careful though to score the draw properly here, if you are one ply off, terrible things may happen)
And keep in mind that mate right on the 50th move trumps the draw even if the mate move is neither a capture nor a pawn move.
mar wrote: Tue Oct 27, 2020 9:45 pmwell, why not do this inside qsearch?
Because QS should deal with capture moves which would reset the draw counter anyway. Doing the move history check in QS looks like a waste of time. That should only be done in main search before and instead of iterating any deeper. So, in the move loop after making the current move, but before the recursion.
are you sure it detects repetition in the game history before root move as well?
That's a very probable cause here.
Rasmus Althoff
https://www.ct800.net
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Make engine stop repeating moves in a clearly won position

Post by mar »

Ras wrote: Tue Oct 27, 2020 9:56 pm Because QS should deal with capture moves which would reset the draw counter anyway. Doing the move history check in QS looks like a waste of time. That should only be done in main search before and instead of iterating any deeper. So, in the move loop after making the current move, but before the recursion.
I do this and I'm happy with that. Note that I also do checks at depth 0 and evasions everywhere, my draw detection also handles draws by insufficient material.
as for performance, I don't think that probing a rep hash/iterating history list in each qs node would be something you could even measure.
and don't forget that each capture will naturally reset rep hash/history, so the cost is basically completely eliminated in subsequent nodes
Martin Sedlak
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Make engine stop repeating moves in a clearly won position

Post by mvanthoor »

mar wrote: Tue Oct 27, 2020 9:45 pm also: are you sure it detects repetition in the game history before root move as well? (since last irreversible move)?
I might not be understand this correctly. Let's say, we have the following 50 move rule count:

1 2 3 4 5 6 0 1 2 3 4 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6

At the 0, an irreversible move happens. in the last 6 ply, the position can not have been repeated.

In total, there are 26 ply. The 50 move rule counter is at 6, so the ply that reset the move counter was 20.

(history length - move counter = 26 - 6 = 20.)

So I search repetitions from 0 up to and including 19. (i = 0; i < length - move_counter; i++).

As far as I can see this should be correct, but it seems not to work. When I remove the move_counter calculation and just check the entire history, it does seem to work.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Make engine stop repeating moves in a clearly won position

Post by mar »

but that's wrong. you should search the last 7 positions (or 6, depending on whether it comes before or after the reset)
you don't care about repetitions before last irreversible move.
also, you can only check each other position (you only check reps for side to move)
Last edited by mar on Tue Oct 27, 2020 10:25 pm, edited 1 time in total.
Martin Sedlak