Implementing UCI_LimitStrength / UCI_Elo

Discussion of chess software programming and technical issues.

Moderator: Ras

JoAnnP38
Posts: 253
Joined: Mon Aug 26, 2019 4:34 pm
Location: Clearwater, Florida USA
Full name: JoAnn Peeler

Implementing UCI_LimitStrength / UCI_Elo

Post by JoAnnP38 »

I am considering adding support for the UCI options UCI_LimitStrength / UCI_Elo in a future version of Pedantic. For anyone unfamiliar with these "pseudo-standard" options, they are implemented by both StockFish and Komodo Dragon and they allow the engine to be configured to play at a lower strength. When UCI_LimitStrength is set to "true", then the engine will try to play at the Elo level set by UCI_Elo. Erik Madsen has an excellent blog post on how he implemented this in his engine MadChess. I was thinking that there might be a simpler (dumbed-down) way to implement this based on mostly manipulating the values return by my evaluation routine. For example:

NerfedEvalScore = EvalScore - NerfPercent * EvalScore + RandomNormalized(NerfPercent * EvalScore, NerfStandardDev).

Like NerfPercent, NerfStandardDev would need to be determined via trial and error.

Then I would need to map NerfPercent to various Elo strength with perhaps linear extrapolation if UCI_Elo is set to an in-between value.

Then I would also use NerfPercent to also nerf the NPS of the engine or else it would still be strong in finding mates or draws. To do this I can just waste time in my clock check whenever the current NPS exceeds the calculated nerfed NPS.

I wanted to implement this feature with as little effort as possible and with as little probability of introducing bugs into my regular search/evaluation.

Does what I've described above sound like a "reasonable" approach?
syzygy
Posts: 5694
Joined: Tue Feb 28, 2012 11:56 pm

Re: Implementing UCI_LimitStrength / UCI_Elo

Post by syzygy »

JoAnnP38 wrote: Thu Jul 27, 2023 8:37 pm I am considering adding support for the UCI options UCI_LimitStrength / UCI_Elo in a future version of Pedantic. For anyone unfamiliar with these "pseudo-standard" options, they are implemented by both StockFish and Komodo Dragon and they allow the engine to be configured to play at a lower strength. When UCI_LimitStrength is set to "true", then the engine will try to play at the Elo level set by UCI_Elo. Erik Madsen has an excellent blog post on how he implemented this in his engine MadChess. I was thinking that there might be a simpler (dumbed-down) way to implement this based on mostly manipulating the values return by my evaluation routine. For example:

NerfedEvalScore = EvalScore - NerfPercent * EvalScore + RandomNormalized(NerfPercent * EvalScore, NerfStandardDev).

Like NerfPercent, NerfStandardDev would need to be determined via trial and error.

Then I would need to map NerfPercent to various Elo strength with perhaps linear extrapolation if UCI_Elo is set to an in-between value.

Then I would also use NerfPercent to also nerf the NPS of the engine or else it would still be strong in finding mates or draws. To do this I can just waste time in my clock check whenever the current NPS exceeds the calculated nerfed NPS.

I wanted to implement this feature with as little effort as possible and with as little probability of introducing bugs into my regular search/evaluation.

Does what I've described above sound like a "reasonable" approach?
The "problem" with adding a random error to the evaluation of leaf nodes is that these errors will quickly average out. (It may not be a real problem if you make the errors large enough.)

My preferred approach would be to instead add errors/boni to the evaluation of root moves.

Before you start searching, assign each root move i a bonus b[ i ].
Then search root move i not with

Code: Select all

  v = -search(pos, -beta, -alpha, depth - 1);
but with

Code: Select all

  v = b[i] - search(pos, b[i] - beta, b[i] - alpha, depth - 1);
A long time ago I used this to stop my single-threaded engine from being too deterministic the first couple of moves out of book.

I am not claiming that your approach does not work or that my approach is better. I do not know what is better, only what I would try first.

See also this thread:
viewtopic.php?f=7&t=81028