
For the upcoming version 2.4 I want to focus on the search again. So far I have two small changes that are uncontroversial:
1.) I had implemented SEE a while ago already but only now managed to make it fast enough that it gave me a strength increase when used in QSearch.
2.) I also added the condition that a position should at least have a static evaluation greater alpha to be eligible for null move pruning. (because the null move tries to find positions that are too good it doesn't make much sense to even start it on positions that look terrible)
And that brought my attention to the other use-case of the static eval in my search:
Code: Select all
const int MAX_GAIN_PER_PLY = 70; //upper bound on the amount of cp you can hope to make good in a ply
const int FUTILITY_RANGE = 4;
bool interesting = playState.Stage == Stage.PV|| inCheck || next.InCheck();
if (remaining <= FUTILITY_RANGE && !interesting)
{
//if the static eval looks much worse than alpha also skip it
float futilityMargin = alpha - remaining * MAX_GAIN_PER_PLY;
if (next.RelativeScore(current.SideToMove) < futilityMargin)
continue;
}
Here is an example of what Leorik could no longer solve:
[fen]1nbq1r1k/3rbp1p/p1p1pp1Q/1p6/P1pPN3/5NP1/1P2PPBP/R4RK1 w - -[/fen]
The best move is to sacrifice the Knight with 'Nfg5'.
But in actual play the version didn't do so bad so I thought I should give it a real chance. After a few iterations the code looked like this:
Code: Select all
if (!interesting && !Evaluation.IsCheckmate(Score))
{
//if the static eval looks much worse than alpha also skip it
int margin = playState.Stage == Stage.Quiets ? _options.LateFutilityMargin : _options.FutilityMargin;
float futilityMargin = alpha - remaining * margin;
if (next.RelativeScore(current.SideToMove) < futilityMargin)
continue;
}

...and the predicted Elo gain was actually reproducable both in self-play matches

and in a gauntlet against other engines.
I could be very happy about the +20 Elo gain if it didn't come with the above described weakness of making the engine much worse in reasoning about one of the coolest type of moves: sacrifices!
Since then I have tried to find a way of keeping the strength increase from skipping *all* bad looking moves regardless of depth while also retaining the ability to solve all the puzzles that Leorik could solve before the change. Sadly so far I haven't found the right approach and I start to fear these goals are mutually exclusive.
Suggestions are welcome!
