
New engine: Peacekeeper
Moderator: Ras
-
- Posts: 66
- Joined: Thu Dec 09, 2021 8:26 pm
- Full name: Kyle Zhang
Tuned Tables
I have released v1.0, which has tuned piece square tables. They seem to be around the strength of the PeSTO tables, so I have gone with them. Other bit of search modifications, and the engine seems a bit stronger (but still weaker than those of other people around here). However finally the important components of Peacekeeper are original! 

Peacekeeper: https://github.com/Sazgr/peacekeeper/
-
- Posts: 66
- Joined: Thu Dec 09, 2021 8:26 pm
- Full name: Kyle Zhang
Re: New engine: Peacekeeper
Release v1.01 to fix a crashing bug: https://github.com/Sazgr/peacekeeper/releases/tag/v1.01
Aside from fixing that bug though, I've been making no other progress at all which I suspect may have to do with extremely messy code. Almost no comments at all, pain in the neck to add on new features such as killer tables or pawn hash. I suppose I will have to do a major code restructuring before continuing progress
Aside from fixing that bug though, I've been making no other progress at all which I suspect may have to do with extremely messy code. Almost no comments at all, pain in the neck to add on new features such as killer tables or pawn hash. I suppose I will have to do a major code restructuring before continuing progress

Peacekeeper: https://github.com/Sazgr/peacekeeper/
-
- Posts: 440
- Joined: Thu Apr 26, 2012 1:51 am
- Location: Oak Park, IL, USA
- Full name: Erik Madsen
Re: New engine: Peacekeeper
Hang in there. It's all part of the learning process.
I do recommend incrementally refactoring code to keep it clean. You don't want to accumulate such a mess that you're discouraged from working on your engine. Make small changes, then run a gauntlet tournament to ensure you didn't introduce a performance regression. Accept the fact that part of chess programming is waiting for game results.
I do recommend incrementally refactoring code to keep it clean. You don't want to accumulate such a mess that you're discouraged from working on your engine. Make small changes, then run a gauntlet tournament to ensure you didn't introduce a performance regression. Accept the fact that part of chess programming is waiting for game results.
Erik Madsen | My C# chess engine: https://www.madchess.net
-
- Posts: 915
- Joined: Sun Dec 27, 2020 2:40 am
- Location: Bremen, Germany
- Full name: Thomas Jahn
Re: New engine: Peacekeeper
That's solid advice!emadsen wrote: ↑Wed Jan 04, 2023 1:19 am I do recommend incrementally refactoring code to keep it clean. You don't want to accumulate such a mess that you're discouraged from working on your engine. Make small changes, then run a gauntlet tournament to ensure you didn't introduce a performance regression. Accept the fact that part of chess programming is waiting for game results.
If you don't test every new feature in isolation and instead make a bunch of changes and test them together you'll risk that some features become part of your engine that are underperforming. Good luck finding these problematic parts later!
Even if you test thoroughly the question is: how much Elo should a new feature add so that you can be pretty sure it's not underperforming? I haven't found a good answer to that one but reading the forum helps.
Besides running selfplay matches or gauntlets (and enough of them for the results to be statistically significant) I found it useful to have a set of a few hundred positions with a known best move. You can search all positions in the testset to a specific depth and see how many correct moves you found and how long that took. When you are just refactoring or performance optimizing you can skip the gauntlet test as long as the duration of the test goes down while the number of solved positions and total number of searched nodes stay the same. Making your program just faster is never a reason for concern.
-
- Posts: 66
- Joined: Thu Dec 09, 2021 8:26 pm
- Full name: Kyle Zhang
Re: New engine: Peacekeeper
Hi, thank you two!lithander wrote: ↑Wed Jan 04, 2023 1:34 pmThat's solid advice!emadsen wrote: ↑Wed Jan 04, 2023 1:19 am I do recommend incrementally refactoring code to keep it clean. You don't want to accumulate such a mess that you're discouraged from working on your engine. Make small changes, then run a gauntlet tournament to ensure you didn't introduce a performance regression. Accept the fact that part of chess programming is waiting for game results.
If you don't test every new feature in isolation and instead make a bunch of changes and test them together you'll risk that some features become part of your engine that are underperforming. Good luck finding these problematic parts later!
Even if you test thoroughly the question is: how much Elo should a new feature add so that you can be pretty sure it's not underperforming? I haven't found a good answer to that one but reading the forum helps.
Besides running selfplay matches or gauntlets (and enough of them for the results to be statistically significant) I found it useful to have a set of a few hundred positions with a known best move. You can search all positions in the testset to a specific depth and see how many correct moves you found and how long that took. When you are just refactoring or performance optimizing you can skip the gauntlet test as long as the duration of the test goes down while the number of solved positions and total number of searched nodes stay the same. Making your program just faster is never a reason for concern.
At the early stages of development I neglected to test some features, so now I am disabling features one by one to see elo gain separately. I will look into testsets such as the WAC. Hopefully I can find some features that are not working up to their full strength. LMR may be a culprit, as in tests, it gives a benefit of usually in the 10-20 elo range which seems suspiciously low.
On another note, right now I am using 5+0.05 time control with concurrency 4 on a laptop with 4 cores and 8 processors (I also do work simultaneously). Should I modify any of those settings for testing matches?
Thank you for all these suggestions

Peacekeeper: https://github.com/Sazgr/peacekeeper/
-
- Posts: 127
- Joined: Sat Jul 30, 2022 12:12 pm
- Full name: Jamie Whiting
Re: New engine: Peacekeeper
Congratulations on the release!Sazgr wrote: ↑Tue Jan 03, 2023 9:34 pm Release v1.01 to fix a crashing bug: https://github.com/Sazgr/peacekeeper/releases/tag/v1.01
Aside from fixing that bug though, I've been making no other progress at all which I suspect may have to do with extremely messy code. Almost no comments at all, pain in the neck to add on new features such as killer tables or pawn hash. I suppose I will have to do a major code restructuring before continuing progress![]()
At first glance there's a lot of the below in your pvs and quiescence code that makes it pretty difficult to read, imo.
Code: Select all
if (!(nodes & 8191) && timer.check(nodes)) {/* something */; return 0;}
-
- Posts: 563
- Joined: Sat Mar 25, 2006 8:27 pm
- Location: USA
- Full name: Robert Pope
Re: New engine: Peacekeeper
If he doesn't check in quiesce, doesn't he risk going many multiples of 8192 without checking, since many will occur in quiesce?
-
- Posts: 127
- Joined: Sat Jul 30, 2022 12:12 pm
- Full name: Jamie Whiting
Re: New engine: Peacekeeper
Good point, he could also check at the top of quiescence as well then, though I've never had any issue not doing that (although I check every 2048 nodes) as these small blocks of nodes are completed so quickly.Robert Pope wrote: ↑Thu Jan 05, 2023 6:33 pm If he doesn't check in quiesce, doesn't he risk going many multiples of 8192 without checking, since many will occur in quiesce?
Either way its way more readable than having code for checking over a dozen times at different locations.
-
- Posts: 66
- Joined: Thu Dec 09, 2021 8:26 pm
- Full name: Kyle Zhang
Re: New engine: Peacekeeper
But say the time allocated by the time management is all used up, and I returned 0 from a PVS call. On the PVS call it returned to, if there is only a check at the top, the outer PVS call will proceed semi-normally. So I put a check after each call of PVS as well. How else should I arrange the checks so that I don't need as much of them? Or will not checking after PVS calls work fine? I am not sure.JacquesRW wrote: ↑Thu Jan 05, 2023 6:30 pmCongratulations on the release!Sazgr wrote: ↑Tue Jan 03, 2023 9:34 pm Release v1.01 to fix a crashing bug: https://github.com/Sazgr/peacekeeper/releases/tag/v1.01
Aside from fixing that bug though, I've been making no other progress at all which I suspect may have to do with extremely messy code. Almost no comments at all, pain in the neck to add on new features such as killer tables or pawn hash. I suppose I will have to do a major code restructuring before continuing progress![]()
At first glance there's a lot of the below in your pvs and quiescence code that makes it pretty difficult to read, imo.But you only really need to do this right at the top of the pvs function (and not at all in quiescence), and the search will probably be faster from not having to check so many branches in each node.Code: Select all
if (!(nodes & 8191) && timer.check(nodes)) {/* something */; return 0;}
Peacekeeper: https://github.com/Sazgr/peacekeeper/
-
- Posts: 127
- Joined: Sat Jul 30, 2022 12:12 pm
- Full name: Jamie Whiting
Re: New engine: Peacekeeper
Mine goes like thisSazgr wrote: ↑Thu Jan 05, 2023 7:31 pm But say the time allocated by the time management is all used up, and I returned 0 from a PVS call. On the PVS call it returned to, if there is only a check at the top, the outer PVS call will proceed semi-normally. So I put a check after each call of PVS as well. How else should I arrange the checks so that I don't need as much of them? Or will not checking after PVS calls work fine? I am not sure.
Code: Select all
fn search(...) {
if (stop) {return 0;}
if (!(nodes & 2047) && check_time() > allocated time) {
stop = true;
return 0;
}
...
}
One part where it is important though, is to make sure you don't write to the hash table (or other tables) with one of these values, so just adding
Code: Select all
if (!stop && /* other conditions */) { hash_table.push(...) }