Devlog of Leorik

Discussion of chess software programming and technical issues.

Moderator: Ras

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 »

Not really a progress update but I did an experiment that I wanted to share here.

My move-gen is pseudo legal which means that each move is technically possible to be played but some are creating a position where the moving side is in check afterwards. To detect those moves I just play each move first and then see if the king is attacked and if it is I'll just skip calling Evaluate on the resulting position. And I'm also not counting the position as a node visited even though a lot time has already been spent on it.

So half-jokingly I thought if I would count them too my nodes per second would appear much higher! You know... for bragging rights. But this gave me an idea... wouldn't it be fair to count the moves if I then also played them normally? What would happen? In Evaluation - regardless of the depth - captures would be generated for each position (Qsearch) and for an illegal position one capture is going to be targeting the King. The move ordering would pick this move to be played first. Now in the resulting position a king would be missing which is trivial to check by just logical-anding together two bitboards and if there's no bit remaining (KINGS & WHITE == 0) the side has no king. In that case I was returning the checkmate score and the whole branch would fail beta for the side capturing the king. And... everything still works!

It's a lot of extra work to play out these captures. But only after an illegal move was made, in all other cases it's saving the effort of doing the legality check. I could have imagined this to be winning bargain.

But alas, it wasn't.

Then I thought about a small optimization: Why even play the king capture? It's cheap to know that the move is targeting a king without playing it. So I was just returning the appropriate checkmate-score immediately. Now the tradeoff is, that I save the legality check on *all* moves but on some moves (that are illegal) you waste time: you play it, pass it on to the next Eval() step where you have to generate all the captures, look once at the movelist (pick the best move) and only then you realize that this position was in fact the result of an illegal move.

Code: Select all

Searching IterativeSearch(7)
Searched 300 positions with IterativeSearch(7)
3868798K nodes visited. Took 303,228 seconds!
12758K NPS.
Best move found in 255 / 300 positions!

Searching IterativeSearchNext(7)
Searched 300 positions with IterativeSearchNext(7)
6053496K nodes visited. Took 366,23 seconds!
16529K NPS.
Best move found in 254 / 300 positions!
The second result is the version playing and then recovering from illegal moves. The nps went up but other than that it's sadly not better!

Maybe for other engines it could turn out differently? I just thought it was interesting enough to share it here.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
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 »

Too many words for me to keep in memory. The way I do this in RomiChess and Bricabrac is while generating moves all captures are accumulated in one u64. After all moves have been generated it becomes as easy as if (captures & king[1 - stm]) return ILLEGAL;. Anyway:

There is a hundred game match going on between Leo and Bric. Bric has a slight lead.

Bricabrac - Leorik.Engine : 18.5/34 13-10-11 (==10110=01==0110===1==111=01001100) 54% +28

A two piece sacrifice.
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: Wed Feb 02, 2022 5:50 am Too many words for me to keep in memory. The way I do this in RomiChess and Bricabrac is while generating moves all captures are accumulated in one u64. After all moves have been generated it becomes as easy as if (captures & king[1 - stm]) return ILLEGAL;
Sorry for being so verbose. I'll try to keep my posts shorter in the future.

Do you use the 'captures' bitboard for anything else?
Mike Sherwin wrote: Wed Feb 02, 2022 5:50 am A two piece sacrifice.
It's astonishing to me how well an engine plays already that has no features other than mvv-lva move sorting, alpha/beta (q)search and PSTs. After adding a TT it would probably see something like the forced mate sequence it was getting caught in, too.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
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: Wed Feb 02, 2022 10:57 am
Mike Sherwin wrote: Wed Feb 02, 2022 5:50 am Too many words for me to keep in memory. The way I do this in RomiChess and Bricabrac is while generating moves all captures are accumulated in one u64. After all moves have been generated it becomes as easy as if (captures & king[1 - stm]) return ILLEGAL;
Sorry for being so verbose. I'll try to keep my posts shorter in the future.

Do you use the 'captures' bitboard for anything else?
Mike Sherwin wrote: Wed Feb 02, 2022 5:50 am A two piece sacrifice.
It's astonishing to me how well an engine plays already that has no features other than mvv-lva move sorting, alpha/beta (q)search and PSTs. After adding a TT it would probably see something like the forced mate sequence it was getting caught in, too.
On a brighter note, Leorik did win the match. Congrats! :D
Leorik.Engine - Bricabrac : 51.5/100 37-34-29 (==01001=10==1001===0==000=10110011100=111101010=11=000=00=11=0111=1111=01==100==1=1=0111=0==00=10100) 52% +14
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: Wed Feb 02, 2022 10:57 am It's astonishing to me how well an engine plays already that has no features other than mvv-lva move sorting, alpha/beta (q)search and PSTs. After adding a TT it would probably see something like the forced mate sequence it was getting caught in, too.
Tapered evaluation was a game changer, IMHO. In Rustic (as in MMC, and probably any engine with a similar feature set) the addition of a tapered PST adds 250 Elo off the bat. In the 90's, with the slower computers of the time, it was really hard to create an engine that played over 2000 Elo; you really needed all the tricks and optimizations you could get. Nowadays computers are fast enough to go 8-10 moves deep even with a very basic setup such as the one Rustic Alpha 3 now uses, in combination with a tapered PST, and they already reach >=2100 Elo on the CCRL-list. These engines are already very hard to defeat tactically, for most amateur players. (Though they can quite easily be outplayed positionally.)

I really look forward to getting out of the XBoard quagmire (and even get through with writing the tuner) so I can add some strength to my engine again.
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 »

mvanthoor wrote: Wed Feb 02, 2022 4:49 pm Tapered evaluation was a game changer, IMHO. In Rustic (as in MMC, and probably any engine with a similar feature set) the addition of a tapered PST adds 250 Elo off the bat.
I've now added a TT to Leorik. And I thought that would make my feature set comparable with Rustic Alpha 2 with only two differences:
- Leorik has the tapered eval that Minimal Chess used in version 0.4.
- Leorik does not yet do any move ordering based on the TT's best-move.

For minimal chess playing the best move from a previous iteration first was such a huge win that I thought this would maybe balance out but in fact Leorik enjoys a comfortable lead so the benefit of the tapered eval must indeed be huge!

Code: Select all

Score of Leorik 0.2 vs Rustic 2: 823 - 205 - 170  [0.758] 1198
...      Leorik 0.2 playing White: 412 - 109 - 78  [0.753] 599
...      Leorik 0.2 playing Black: 411 - 96 - 92  [0.763] 599
...      White vs Black: 508 - 520 - 170  [0.495] 1198
Elo difference: 198.3 +/- 20.6, LOS: 100.0 %, DrawRatio: 14.2 %
The next features I'm going to add are: TT move first, PVS search and killer moves.

Each of them should only make the engine faster but shouldn't cause it to miss anything going on within it's horizon. This opens up another way of testing the engine for correctness: It should be able to solve all mate puzzles in the minimal amount of iterative deepenings. So a mate in 5 should be found at depth 9. A mate in 6 at depth 11 and a mate in 7 exactly at depth 13 and so on...
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
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: Sat Feb 05, 2022 2:15 am For minimal chess playing the best move from a previous iteration first was such a huge win that I thought this would maybe balance out but in fact Leorik enjoys a comfortable lead so the benefit of the tapered eval must indeed be huge!

Code: Select all

Score of Leorik 0.2 vs Rustic 2: 823 - 205 - 170  [0.758] 1198
...      Leorik 0.2 playing White: 412 - 109 - 78  [0.753] 599
...      Leorik 0.2 playing Black: 411 - 96 - 92  [0.763] 599
...      White vs Black: 508 - 520 - 170  [0.495] 1198
Elo difference: 198.3 +/- 20.6, LOS: 100.0 %, DrawRatio: 14.2 %
The next features I'm going to add are: TT move first, PVS search and killer moves.
Yes, current Rustic 4-dev (which implements only tapered evaluation on top of Alpha 3 with regard to new chess playing capability) is ~2160 CCLR blitz, which is ~290 points stronger than Rustic Alpha 3. I know that about 40-50 Elo comes from some tweaks in time management and TT-handling, especially on faster time controls. Thus ~240-250 Elo has to come from the tapered evaluation.

If you have MMV-LVA, TT, TT-move ordering, killer moves and a tapered evaluation, you should be exactly on par with Rustic 4-dev, feature-wise.

Yesterday I have finally finished the (massive...) refactoring process and started the implementation of the last two XBoard things: handling of official FIDE-rule draws by insufficient material (which are _different_ from draws with insufficient material that can't force mate... I never knew that, TBH), and GameTime time management.

After this is done I can _finally_ start on the tuner, and that would be the last part of Rustic 4. Then I can _finally_ drop Alpha from the name, and implement Null Move and Static Null move for version 5.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
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 »

I can't delete the last two sentences anymore. I've just written a more extensive progress post / rant.

Update on Rustic
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 »

I thought I could update here whenever I add another feature and post how much ELO in self play that brought. That was information I was really missing when writing MinimalChess... I was never sure if a feature was working correctly because it wasn't clear how much benefit to expect.

So adding the TT to avoid researching know positions and avoid stupid draws was worth 220 ELO.

Code: Select all

Score of Leorik 0.2 vs Leorik 0.1: 1133 - 126 - 444  [0.796] 1703
Elo difference: 236.1 +/- 15.8, LOS: 100.0 %, DrawRatio: 26.1 %
(This test also included a minor change of the PSTs worth 16 ELO in isolation. 236 - 16 = 220)

Adding TT-move ordering, in so far, as I'm now storing the best (known) move for a position in the TT and play that first before generating any captures or quiets was worth another 150 ELO.

Code: Select all

Score of Leorik 0.2.3 vs Leorik 0.2: 712 - 220 - 269  [0.705] 1201
Elo difference: 151.2 +/- 18.4, LOS: 100.0 %, DrawRatio: 22.4 %
To roughly(!!) guess the CCRL Elo of the current version I played against MinimalChess 0.5 which is rated 2267. MinimalChess 0.5 is still 112 ELO (+-21) better and so a very dumb guess would put Leorik 0.2.3 at 2150 CCRL ELO.

Code: Select all

Score of Leorik 0.2.3 vs MinimalChess 0.5: 192 - 453 - 188  [0.343] 833
Elo difference: -112.6 +/- 21.5, LOS: 0.0 %, DrawRatio: 22.6 %
mvanthoor wrote: Sat Feb 05, 2022 6:27 pm If you have MMV-LVA, TT, TT-move ordering, killer moves and a tapered evaluation, you should be exactly on par with Rustic 4-dev, feature-wise.
I don't have killer moves yet and I don't know if you use PVS in Rustic 4-dev? Because that's what I'm going to implement next, even before killer moves.

Of course with every feature the raw NPS suffers slightly. Writing and reading the TT isn't free! But to the best of my knowledge I'm counting nodes-per-second the same as in MinimalChess and the speed difference is very satisfying. MMC 0.5 reports around 1.3M nps while Leorik does around 9M nps in a midgame position.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
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: Sat Feb 05, 2022 11:22 pm ...
The feature set of my current dev version is MVV-LVA, TT, TT-move ordering, killers, PVS, and tapered evaluation (using MinimalChess' tables; first version. I didn't update to any retuned tables).

I find your numbers hard to believe. Did you add the TT after the tapered evaluation? Maybe you are seeing strength gains that you would normally have seen in the tapered evaluation, if you had added the TT first and THEN the tapered eval.

I added the TT right after the basic version, and the TT-cuts + TT-move sorting gained ~150 Elo, which was in line with other engines at the same time control. I just started a match with my dev version against itself, with one of them having 0 MB for the TT, which will obviously disable it. It seems to hover roughly around -185 for the version without TT:

Code: Select all

Score of Rustic Alpha 3.43.100 vs Rustic Alpha NoTT 3.43.100: 581 - 135 - 204 [0.742]
...      Rustic Alpha 3.43.100 playing White: 319 - 60 - 81  [0.782] 460
...      Rustic Alpha 3.43.100 playing Black: 262 - 75 - 123  [0.703] 460
...      White vs Black: 394 - 322 - 204  [0.539] 920
Elo difference: 183.9 +/- 21.6, LOS: 100.0 %, DrawRatio: 22.2 %
920 of 1500 games finished.
There are about 40 points of refactoring and tweaking in this version, that weren't in Alpha 1 and 2, so these could account for the difference between ~145 and ~185 Elo.

Also, you're searching 9M moves/sec? I assume that is due to your faster CPU. I'll have to run the dev-version you sent me, because while I can believe that Leorik is _much_ faster than MinimalChess, I can't really believe that it is faster than Rustic, on the same hardware, especially because you seem to have chosen a bitboard implementation that is different from, and slower than Fancy Magic. (According to dangi's tests where he runs all the different bitboard algorithms in a speed test).
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL