Devlog of Leorik

Discussion of chess software programming and technical issues.

Moderator: Ras

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

Re: Devlog of Leorik

Post by mvanthoor »

lithander wrote: Sun Mar 06, 2022 9:40 am Back in the day I would have blogged about it. But the forum has the advantage that it comes with an audience! ;)
Rustic's site has more traffic than I would have expected, to be honest.
That puts it already in spitting distance to MadChess, which is the strongest classical C# engine I know of. Is there a stronger one?
I don't know...
With the fix from Version 1.3. already in Leorik would have been faster than Rustic, though. And I found it not completely trivial to preserve that speed while adding more features even if it's only about pruning. History pruning especially cost me a lot of NPS... but it's still 5x faster than MMC.
The date that C# becomes faster than languages such as C and Rust will be the day that pigs fly and hell freezes over. I will probably stop programming and switch to psychology or something. I'll have to profile the engine again to see if I can improve speed somewhere, but I doubt it, to be honest.

With regard to the speed increase... it looks like as if Leorik is now counted nodes that are entered but exited really quickly due to a cutoff; so they don't do any actual work. That would explain the speed increase. Pruning can make the engine visit more nodes/second because it cuts them faster, which increases NPS, but it does not make the engine any faster.

How much Elo did you get from History, separately, before you implemented LMR? Or didn't you test that?
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: Devlog of Leorik

Post by lithander »

The date that C# becomes faster than languages such as C and Rust will be the day that pigs fly and hell freezes over. I will probably stop programming and switch to psychology or something. I'll have to profile the engine again to see if I can improve speed somewhere, but I doubt it, to be honest.
Agreeing to that would just mean that Leorik could be even faster if I did the same thing in C or Rust. But we - you and I - are not doing the same thing so comparing speed and drawing conclusions about what programming language is faster is a bit... unscientific. ;)
With regard to the speed increase... it looks like as if Leorik is now counted nodes that are entered but exited really quickly due to a cutoff; so they don't do any actual work. That would explain the speed increase. Pruning can make the engine visit more nodes/second because it cuts them faster, which increases NPS, but it does not make the engine any faster.
That I count these nodes in qsearch is not new to Leorik 1.5. I counted exactly the same way in version 1.0... and afaik everybody counts those nodes. You do too!

Code: Select all

pub fn quiescence(mut alpha: i16, beta: i16, pv: &mut Vec<Move>, refs: &mut SearchRefs) -> i16 {
        // We created a new node which we'll search, so count it.
        refs.search_info.nodes += 1;

        // Do a stand-pat here: Check how we're doing, even before we make
        // a move. If the evaluation score is larger than beta, then we're
        // already so bad we don't need to search any further. Just return
        // the beta score.
        let eval_score = evaluation::evaluate_position(refs.board);
        if eval_score >= beta {
            return beta;
        }
}
The cheapest way to raise the node Counter in Leorik is also a very cheap node in Rustic too. But how would you justify not counting them?
How much Elo did you get from History, separately, before you implemented LMR? Or didn't you test that?
I talked about it briefly in the Version 1.4 section. I tried a dozen different variants but didn't manage to get over 10 ELO and you know how hard it is to proof that +10 ELO isn't a statistical fluke. So it's safe to say that for Leorik history heuristics are so costly performance wise that they need late move reductions before they become worth it. But every engine is different!

I have now made the test of measuring the percentage of qsearch nodes of all nodes encountered and counted. I used the 300 WAC positions that I always use for testing and a fixed depth.

Leorik 1.0

Depth 4, QNodes 92%, 4120K NPS.
Depth 5, QNodes 93%, 7221K NPS.
Depth 6, QNodes 88%, 5905K NPS.
Depth 7, QNodes 91%, 7932K NPS.
Depth 8, QNodes 86%, 5491K NPS.
Depth 9, QNodes 90%, 7609K NPS.
Depth 10, QNodes 85%, 5249K NPS.

Leorik 1.0 with Piece encoded in 'byte' (the Version 1.3 fix)

Depth 4, QNodes 92%, 5520K NPS.
Depth 5, QNodes 93%, 11199K NPS.
Depth 6, QNodes 88%, 9778K NPS.
Depth 7, QNodes 91%, 12527K NPS.
Depth 8, QNodes 86%, 9511K NPS.
Depth 9, QNodes 90%, 12302K NPS.
Depth 10, QNodes 85%, 9262K NPS.

Leorik 1.5

Depth 5, QNodes 96%, 5343K NPS.
Depth 6, QNodes 94%, 5837K NPS.
Depth 7, QNodes 93%, 6735K NPS.
Depth 8, QNodes 92%, 7048K NPS.
Depth 9, QNodes 92%, 7036K NPS.
Depth 10, QNodes 91%, 7034K NPS.
Depth 11, QNodes 90%, 6822K NPS.
Depth 12, QNodes 89%, 6716K NPS.
Depth 13, QNodes 88%, 6463K NPS.
Depth 14, QNodes 87%, 6366K NPS.
Depth 15, QNodes 87%, 6136K NPS.
Depth 16, QNodes 86%, 6170K NPS.

For me the measurements seem to make perfect sense!

And by all means if you believe my reported NPS are too high you are welcome to critically review the code of my search. There's no hidden modifier like certain other engines use :wink: and to the best of my knowledge I count as conservatively as possible. While the engine is not open source (yet) the source code is on github in a public repo specifically because I want to be 100% transparent in what Leorik does. If there's anything wrong, counted twice or otherwise fishy let me know and I'll fix the bug asap.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
User avatar
emadsen
Posts: 440
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: Devlog of Leorik

Post by emadsen »

lithander wrote: Sat Mar 05, 2022 5:43 pm The current version of Leorik is already about 150 ELO stronger than MMC even though there's not a single feature in Leorik that MMC is missing. Only implementation details and most importantly: Raw speed!
Excellent progress, Thomas. Strong for a minimal code base. I ran a quick gauntlet against MadChess 3.1 (beta). I got the following results for 2m + 1s bullet games.

Code: Select all

Score of MadChess 3.1 vs Leorik 1.5: 198 - 72 - 130 [0.657]
...      MadChess 3.1 playing White: 99 - 33 - 68  [0.665] 200
...      MadChess 3.1 playing Black: 99 - 39 - 62  [0.650] 200
...      White vs Black: 138 - 132 - 130  [0.507] 400
Elo difference: 113.3 +/- 28.7, LOS: 100.0 %, DrawRatio: 32.5 %
400 of 400 games finished.
MadChess 3.1 (beta) is 2664 Elo so that puts Leorik around 2551, give or take about 30 Elo.
Erik Madsen | My C# chess engine: https://www.madchess.net
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Devlog of Leorik

Post by Mike Sherwin »

mvanthoor wrote: Sun Mar 06, 2022 11:54 am
lithander wrote: Sun Mar 06, 2022 9:40 am Back in the day I would have blogged about it. But the forum has the advantage that it comes with an audience! ;)
Rustic's site has more traffic than I would have expected, to be honest.
That puts it already in spitting distance to MadChess, which is the strongest classical C# engine I know of. Is there a stronger one?
I don't know...
With the fix from Version 1.3. already in Leorik would have been faster than Rustic, though. And I found it not completely trivial to preserve that speed while adding more features even if it's only about pruning. History pruning especially cost me a lot of NPS... but it's still 5x faster than MMC.
The date that C# becomes faster than languages such as C and Rust will be the day that pigs fly and hell freezes over. I will probably stop programming and switch to psychology or something. I'll have to profile the engine again to see if I can improve speed somewhere, but I doubt it, to be honest.

With regard to the speed increase... it looks like as if Leorik is now counted nodes that are entered but exited really quickly due to a cutoff; so they don't do any actual work. That would explain the speed increase. Pruning can make the engine visit more nodes/second because it cuts them faster, which increases NPS, but it does not make the engine any faster.

How much Elo did you get from History, separately, before you implemented LMR? Or didn't you test that?
I also have a difficult time wrapping my mind around the fact that C# can be so fast. So I researched C# performance and there is one thing I found that I was not aware of. And that is some modern C# variants come with a Jit compiler. And modern Jit compilers can be very fast. And Thomas is a very capable programmer and writes very attractive code. But having said that there is nothing wrong examining his code just incase. 8-)
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Devlog of Leorik

Post by Mike Sherwin »

lithander wrote: Sun Mar 06, 2022 1:08 pm
The date that C# becomes faster than languages such as C and Rust will be the day that pigs fly and hell freezes over. I will probably stop programming and switch to psychology or something. I'll have to profile the engine again to see if I can improve speed somewhere, but I doubt it, to be honest.
Agreeing to that would just mean that Leorik could be even faster if I did the same thing in C or Rust. But we - you and I - are not doing the same thing so comparing speed and drawing conclusions about what programming language is faster is a bit... unscientific. ;)
With regard to the speed increase... it looks like as if Leorik is now counted nodes that are entered but exited really quickly due to a cutoff; so they don't do any actual work. That would explain the speed increase. Pruning can make the engine visit more nodes/second because it cuts them faster, which increases NPS, but it does not make the engine any faster.
That I count these nodes in qsearch is not new to Leorik 1.5. I counted exactly the same way in version 1.0... and afaik everybody counts those nodes. You do too!

Code: Select all

pub fn quiescence(mut alpha: i16, beta: i16, pv: &mut Vec<Move>, refs: &mut SearchRefs) -> i16 {
        // We created a new node which we'll search, so count it.
        refs.search_info.nodes += 1;

        // Do a stand-pat here: Check how we're doing, even before we make
        // a move. If the evaluation score is larger than beta, then we're
        // already so bad we don't need to search any further. Just return
        // the beta score.
        let eval_score = evaluation::evaluate_position(refs.board);
        if eval_score >= beta {
            return beta;
        }
}
The cheapest way to raise the node Counter in Leorik is also a very cheap node in Rustic too. But how would you justify not counting them?
How much Elo did you get from History, separately, before you implemented LMR? Or didn't you test that?
I talked about it briefly in the Version 1.4 section. I tried a dozen different variants but didn't manage to get over 10 ELO and you know how hard it is to proof that +10 ELO isn't a statistical fluke. So it's safe to say that for Leorik history heuristics are so costly performance wise that they need late move reductions before they become worth it. But every engine is different!

I have now made the test of measuring the percentage of qsearch nodes of all nodes encountered and counted. I used the 300 WAC positions that I always use for testing and a fixed depth.

Leorik 1.0

Depth 4, QNodes 92%, 4120K NPS.
Depth 5, QNodes 93%, 7221K NPS.
Depth 6, QNodes 88%, 5905K NPS.
Depth 7, QNodes 91%, 7932K NPS.
Depth 8, QNodes 86%, 5491K NPS.
Depth 9, QNodes 90%, 7609K NPS.
Depth 10, QNodes 85%, 5249K NPS.

Leorik 1.0 with Piece encoded in 'byte' (the Version 1.3 fix)

Depth 4, QNodes 92%, 5520K NPS.
Depth 5, QNodes 93%, 11199K NPS.
Depth 6, QNodes 88%, 9778K NPS.
Depth 7, QNodes 91%, 12527K NPS.
Depth 8, QNodes 86%, 9511K NPS.
Depth 9, QNodes 90%, 12302K NPS.
Depth 10, QNodes 85%, 9262K NPS.

Leorik 1.5

Depth 5, QNodes 96%, 5343K NPS.
Depth 6, QNodes 94%, 5837K NPS.
Depth 7, QNodes 93%, 6735K NPS.
Depth 8, QNodes 92%, 7048K NPS.
Depth 9, QNodes 92%, 7036K NPS.
Depth 10, QNodes 91%, 7034K NPS.
Depth 11, QNodes 90%, 6822K NPS.
Depth 12, QNodes 89%, 6716K NPS.
Depth 13, QNodes 88%, 6463K NPS.
Depth 14, QNodes 87%, 6366K NPS.
Depth 15, QNodes 87%, 6136K NPS.
Depth 16, QNodes 86%, 6170K NPS.

For me the measurements seem to make perfect sense!

And by all means if you believe my reported NPS are too high you are welcome to critically review the code of my search. There's no hidden modifier like certain other engines use :wink: and to the best of my knowledge I count as conservatively as possible. While the engine is not open source (yet) the source code is on github in a public repo specifically because I want to be 100% transparent in what Leorik does. If there's anything wrong, counted twice or otherwise fishy let me know and I'll fix the bug asap.
Hey Thomas, I studied your search and I am very impressed. It has things that I have never seen before (that I remember anyway). You have some early outs that I would not have considered sound. However given your results it can't be bad. Also I see that you (if I understood correctly) generate quiet moves one at a time. Is that correct? So to me it looks like you save a lot of time making your nodes on average very cheap. And that is a good thing. And the bottom line is your node counting looks justified in my opinion. Very good work, Sir. :D
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Devlog of Leorik

Post by mvanthoor »

lithander wrote: Sun Mar 06, 2022 1:08 pm And by all means if you believe my reported NPS are too high you are welcome to critically review the code of my search. There's no hidden modifier like certain other engines use :wink: and to the best of my knowledge I count as conservatively as possible. While the engine is not open source (yet) the source code is on github in a public repo specifically because I want to be 100% transparent in what Leorik does. If there's anything wrong, counted twice or otherwise fishy let me know and I'll fix the bug asap.
Mike Sherwin wrote: Mon Mar 07, 2022 6:25 am I also have a difficult time wrapping my mind around the fact that C# can be so fast.
I'm not suspecting that there is a bug and certainly no manipulation of numbers to artificially increase engine speed. (One would be lying to one-self in that case...) It's just that I can't believe that C# is faster than Rust or C given the same implementation of a feature. If Leorik in C# _IS_ faster than Rustic, I must be the one who is doing something inefficient somewhere.

Also, what throws me off each time is the fact that Thomas runs Leorik on a computer that is 5 years newer than mine. (I still run on a 6700K, a CPU released in the second half of 2015.) Even if both Rustic and Leorik run between 5-7 million NPS on my system, these engines could easily hit 8-12 million NPS on Thomas' Zen 2 CPU. And even more after I upgrade to Zen 4 in 2023... those numbers are incomparable.

But, I'm glad that Leorik's tentative rating is close to 2600 with the feature set it has. That is 100 Elo more than what I had planned for Rustic with that feature set, but that was clearly a conservative estimate. So, if I don't reach 2570 at the very least, I must have done something wrong somewhere (after I actually implement those features).
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: Devlog of Leorik

Post by lithander »

Mike Sherwin wrote: Mon Mar 07, 2022 6:56 am Hey Thomas, I studied your search and I am very impressed. It has things that I have never seen before (that I remember anyway). You have some early outs that I would not have considered sound. However given your results it can't be bad. Also I see that you (if I understood correctly) generate quiet moves one at a time. Is that correct? So to me it looks like you save a lot of time making your nodes on average very cheap. And that is a good thing. And the bottom line is your node counting looks justified in my opinion. Very good work, Sir. :D
Thanks for the kind words. That kind of praise from a veteran such as yourself means a lot.

I only generate quiet moves once the PV move, the captures and the killers have not yielded a beta cutoff. So it's not often that I have to generate quiet moves but if I do then I generate them all in bulk by calling CollectQuiets(). After that I remove the already played killer moves from that list. I could play those moves again and it wouldn't be too bad because I likely get a TT hit. But it's better to just get rid of them here because the next stage is picking quiet moves based on their history score. I don't want to spend the effort of sorting known killers to the front again based on their history score. Once the history-score of next quiet move to play drops below a certain threshold I stop wasting more time on sorting any more moves that I no know will all have a pretty bad history. So I drop out of the SortedQuiets stage into the normal Quiets stage where I just play all the remaining moves in order of appearance and I also reduce them by 2 plys during the PVS step.

What early-out was it that cought your attention as being risky? I would have thought my reductions and prunings are pretty conservative and on the non-agressive side of the spectrum. But I didn't look into the source code of other engines so I can't really compare.
emadsen wrote: Mon Mar 07, 2022 4:43 am Excellent progress, Thomas. Strong for a minimal code base. I ran a quick gauntlet against MadChess 3.1 (beta). I got the following results for 2m + 1s bullet games.

Code: Select all

Score of MadChess 3.1 vs Leorik 1.5: 198 - 72 - 130 [0.657]
...      MadChess 3.1 playing White: 99 - 33 - 68  [0.665] 200
...      MadChess 3.1 playing Black: 99 - 39 - 62  [0.650] 200
...      White vs Black: 138 - 132 - 130  [0.507] 400
Elo difference: 113.3 +/- 28.7, LOS: 100.0 %, DrawRatio: 32.5 %
400 of 400 games finished.
MadChess 3.1 (beta) is 2664 Elo so that puts Leorik around 2551, give or take about 30 Elo.
Thanks for giving Leorik some play! Your results see Leorik as a little weaker than what my own gauntlet would suggest. There Leorik was pretty even with MadChess 3.0, maybe +10 Elo for MadChess. How much stronger in your own tests do you see Madchess 3.1 in comparision with Madchess 3.0?

I'll do some more extensive tests when I have a release candidate for the 2.0 version. For now I test mostly to make sure that new features are performing within expectation.

Speaking of which... the last open issue I want adressed before version 2.0 is that Leorik currently does not properly handle draw rules. I don't track the 50 ply move rule at all and for repetitions I don't track positions encountered during search. Only positions that have actually been seen in the game are scored as leading to a 3-fold repetition but not positions visited during search. This means that in this position

[fen]8/6pk/p7/1p1pQ3/1PpP1K2/8/6q1/8 b - - 9 78[/fen]

Leorik does not see the risk of white using the Queen to perpetually put the black king into check. It will play c3 and then the game ends in a draw even though it should be winning for black.

So version 1.6 has this issue fixed. c4c3 is now properly avoided. But in selfplay the version does not seem any stronger... and I don't really understand it. I can't believe such a situation is so rare that it wouldn't show? So could you help me set the correct expectations?

How much ELO do you expect an engine to gain from becoming aware of the 50 move rule?
How much ELO do you expect an engine to gain from scoring 3-fold-repetitions during search correctly?
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
User avatar
emadsen
Posts: 440
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: Devlog of Leorik

Post by emadsen »

lithander wrote: Tue Mar 08, 2022 9:31 pm Thanks for giving Leorik some play! Your results see Leorik as a little weaker than what my own gauntlet would suggest. There Leorik was pretty even with MadChess 3.0, maybe +10 Elo for MadChess. How much stronger in your own tests do you see Madchess 3.1 in comparision with Madchess 3.0?
Currently, MadChess 3.1 beta is 58 Elo stronger than MadChess 3.0.
lithander wrote: Tue Mar 08, 2022 9:31 pm How much ELO do you expect an engine to gain from becoming aware of the 50 move rule?
How much ELO do you expect an engine to gain from scoring 3-fold-repetitions during search correctly?
I suspect knowledge of 3-fold repetitions is a much greater contributor to engine strength than knowledge of the 50 move rule. I don't have measurements for the 50 move rule, but in an earlier version of my engine, I measured a 47 Elo improvement after fixing a bug related to 3-fold repetitions. See Draw By Repetition Bug for details. However, this was a severe bug causing the engine to play a random move when a draw was within sight. It's likely an upper bound of the expected gain from scoring 3-fold repetitions correctly.
Erik Madsen | My C# chess engine: https://www.madchess.net
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: Devlog of Leorik

Post by lithander »

emadsen wrote: Wed Mar 09, 2022 5:48 am I suspect knowledge of 3-fold repetitions is a much greater contributor to engine strength than knowledge of the 50 move rule. I don't have measurements for the 50 move rule, but in an earlier version of my engine, I measured a 47 Elo improvement after fixing a bug related to 3-fold repetitions. See Draw By Repetition Bug for details. However, this was a severe bug causing the engine to play a random move when a draw was within sight. It's likely an upper bound of the expected gain from scoring 3-fold repetitions correctly.
I tried two implementations in selftest now:

Version 1.6.1 uses a HalfmoveClock and the fact that I have all the boardstates of all previous plies easily accessible in an array.

So can do this:

Code: Select all

private bool IsRepetition(int ply)
{
	for (int i = ply - 4; i >= 0; i -= 2)
		if (Positions[i].ZobristHash == Positions[ply].ZobristHash)
			return true;

	return false;
}

Code: Select all

tc=5+0.3
Score of Leorik 1.6.1 vs Leorik 1.5.1: 881 - 629 - 1422  [0.543] 2932
...      Leorik 1.6.1 playing White: 437 - 309 - 720  [0.544] 1466
...      Leorik 1.6.1 playing Black: 444 - 320 - 702  [0.542] 1466
...      White vs Black: 757 - 753 - 1422  [0.501] 2932
Elo difference: 29.9 +/- 9.0, LOS: 100.0 %, DrawRatio: 48.5 %
---

In the version 1.6.0 I use the TT to mark positions that have already been visited during the current line. If you reach the position again you get a draw score from the TT.

The Evaluation() of a position is wrapped in calls to the TT like this...

Code: Select all

            
ulong hash = Positions[ply].ZobristHash;
if (Transpositions.GetScore(hash, remaining, ply, alpha, beta, out Move bm, out int ttScore))
	return ttScore;

int score = Evaluate(ply, remaining, alpha, beta, moveGen, ref bm);
	
Transpositions.Store(hash, remaining, ply, alpha, beta, score, bm);
...and in the case where GetScore returns false because the position has no usable entry it "knows" that the position is going to be searched and can set the TT entry for that hash to zero and "freeze" by setting the depth to the max value. So from now on visiting this node again will yield a draw score because this leads to a 3-fold repetition. When the search returns calling Store() will automatically unfreeze the position by setting the real score and the correct depth because now it's not a repetition anymore. At least not in the line of the search.

Code: Select all

tc=5+0.3
Score of Leorik 1.6 vs Leorik 1.5.1: 837 - 694 - 1426  [0.524] 2957
...      Leorik 1.6 playing White: 463 - 329 - 687  [0.545] 1479
...      Leorik 1.6 playing Black: 374 - 365 - 739  [0.503] 1478
...      White vs Black: 828 - 703 - 1426  [0.521] 2957
Elo difference: 16.8 +/- 9.0, LOS: 100.0 %, DrawRatio: 48.2 %
Both implementations are pretty simple and they solve the immediate problem with a position like the one I gave in the last post. I think the TT solution is a bit more hacky and intransparent than the HalfmoveClock one. And the latter has the advantage that you can also consider the 50 move rule easily. Last but not least it performed better so that's what I'm going to commit, probably.

I'm almost ready for Version 2.0!

Almost... because I just noticed today that my HashEntry struct is now 24 bytes large instead of the 16 bytes that I assumed. And that means that if you allow Leorik to use 50 MB hash it actually uses 75 MB. I need to change the encoding to a denser format so that I can go back to 16 bytes without losing any information.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Devlog of Leorik - Version 2.0 released

Post by lithander »

I fixed the issue with the TT size and decided that I have everything in place now to release Version 2.0!

Here's the complete feature list:
  • Pseudo-legal move generator, bitboards and copy/make
  • Negamax search with Alpha-Beta Pruning and Iterative Deepening
  • Minimal evaluation based on tapered, tuned PSTs only
  • Incrementally updated evaluation and Zobrist hash
  • Transposition Table with two buckets and aging
  • PVS search (null windows)
  • Futility pruning
  • Null-Move pruning
  • Staged move generation
  • MVV-LVA sorted captures
  • Killers
  • History sorted quiets with LMR
That means Leorik has feature parity with MinimalChass now except for the evaluation where MMC was a little more sophisticated. However Leorik makes that up with raw speed. And not in my wildest dreams did I think that my rewrite would be 7x faster than my first engine. (~7M nps on my computer)

As for what the recent additions mean for Leorik 1.0... this is the match where the engines play without an opening book. I can't help but imagine Leorik 2 to laugh evilly when he's making these two sacrifices in the end. :twisted: :twisted:

[pgn][Event "?"]
[Site "?"]
[Date "2022.03.11"]
[Round "?"]
[White "Leorik 1.0"]
[Black "Leorik 2.0"]
[Result "0-1"]
[ECO "C46"]
[GameDuration "00:02:05"]
[GameEndTime "2022-03-11T22:44:09.192 Mitteleuropäische Zeit"]
[GameStartTime "2022-03-11T22:42:03.941 Mitteleuropäische Zeit"]
[Opening "Four knights game"]
[PlyCount "46"]
[TimeControl "40/60+1"]

1. e4 {+0.08/10 5.9s} e5 {-0.09/17 2.7s} 2. Nf3 {+0.18/9 2.7s}
Nc6 {-0.30/16 3.7s} 3. Nc3 {+0.10/8 0.86s} Nf6 {-0.13/17 4.3s}
4. Bd3 {+0.09/8 1.2s} g6 {-0.01/15 2.1s} 5. O-O {+0.16/9 2.2s}
Bg7 {+0.03/16 2.3s} 6. a3 {+0.07/9 3.3s} O-O {+0.21/17 2.7s}
7. Nd5 {+0.02/9 2.2s} d6 {+0.15/17 2.5s} 8. Re1 {-0.02/9 1.9s}
Be6 {+0.20/16 2.0s} 9. c4 {-0.09/9 3.2s} Nd4 {+0.09/16 6.8s}
10. Nxd4 {-0.03/9 1.2s} exd4 {+0.18/15 1.5s} 11. Nf4 {-0.15/8 1.1s}
Bg4 {+0.11/14 2.0s} 12. f3 {-0.08/9 2.0s} Be6 {+0.06/16 5.7s}
13. b4 {-0.02/8 1.3s} Nd7 {+0.26/16 2.2s} 14. Bb2 {-0.13/9 2.3s}
Qg5 {+0.30/16 3.1s} 15. Nxe6 {-0.32/9 4.5s} fxe6 {+0.42/16 2.3s}
16. Kh1 {-0.39/9 5.4s} Ne5 {+0.44/15 2.5s} 17. Bf1 {-0.39/9 7.2s}
Rf4 {+0.33/14 6.5s} 18. d3 {-0.30/8 1.2s} Rh4 {+1.24/15 2.9s}
19. Be2 {-0.67/8 1.6s} Qg3 {+M9/14 1.00s} 20. h3 {-M8/8 1.0s} Ng4 {+M7/16 2.0s}
21. fxg4 {-M6/9 1.3s} Rxh3+ {+M5/17 1.4s} 22. gxh3 {-M4/10 1.4s}
Be5 {+M3/19 2.0s} 23. Bf1 {-M2/11 4.2s} Qh2# {+M1/20 2.0s, Black mates} 0-1[/pgn]

But Leorik 1.0 has it's merits too as it's solving this position in milliseconds that even Stockfish can't solve! :) (originally found in the expositor thread)
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess