MCEC anyone?

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

Re: MCEC anyone?

Post by mvanthoor »

lithander wrote: Fri Jun 04, 2021 1:18 pm ...
Does MinimalChess have only tapered/tuned PST eval + the extra dynamics table?

I can confirm what Amanj says. MinimalChess has a really strong middle game for its rating. (That is true for 0.4.1 already.) However, if its opponent survives the middle game, it often loses on tactics.

As Amanj says below:
amanjpro wrote: Mon Jun 14, 2021 2:49 am TT really pays off in the ending, I would highly recommend it. It is an easy 100 elos or so
PS: In my engine, the TT gained 140-150 Elo.

Now you're having to decide if you build a TT into MinimalChess, or do a non-minimal rewrite.

This engine thing is never going to end... must have 5 more Elo... :twisted:
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
lithander
Posts: 881
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: MCEC anyone?

Post by lithander »

amanjpro wrote: Mon Jun 14, 2021 2:49 am I have been watching a few games of Minimal Chess, and while in the middle-game and early endgame he often outplays the opponent, no matter which engine it is. When it comes to the finish blow, due to the lack of TT, he often blows the win by not seeing deep enough.

TT really pays off in the ending, I would highly recommend it. It is an easy 100 elos or so
Thanks for the analysis and I think you're spot on. It would be the obvious next step to make the engine play stronger. I'm sure that most if not all engines playing above 2k ELO will have transposition tables.
mvanthoor wrote: Mon Jun 14, 2021 10:24 am Now you're having to decide if you build a TT into MinimalChess, or do a non-minimal rewrite.
That's exactly the thing. There are some basic design decisions like having a copy/make design instead of a make/unmake one that only make sense if the design goal is simplicity.
Transposition tables are all about gaining speed and playing strength not simplicity. So is it about speed now and climbing the ELO ladder? If I change my goal retroactively I should reconsider the design from the ground up. I should also stop writing idiomatic C# code because it's leaving a trail of millions of objects per second on the heap for the garbage collector to clean up. It's how the language is meant to be used but it's not exactly fast.

So, I feel like adding transposition tables now makes sense only if I forsake the goal of minimalism and simplicty. And then I should do a dozen other refactorings, too. And then we are not talking about MinimalChess anymore but something else.
mvanthoor wrote: Mon Jun 14, 2021 10:24 am This engine thing is never going to end... must have 5 more Elo... :twisted:
But is that fun to you? I don't think that's fun for me. Currently I'm trying to add late move reductions because that is a really simple idea and it can be done without adding much extra code. But there are so many variants that I could consider... what is considered a late move? how much do you reduce? And so on... And in every scenario you will pay a price for the additional search depth: Sometimes you'll miss a few good moves because the path to them didn't look too promising and got pruned. And so it remains a trade off even if it gains you a few ELO.

Also whether the tradeoff is a benefit in practice seems to depend a lot on the opponent and the time controls. So it feels like I'm making arbitrary changes that could or could not work and I won't know before i test it. So I'm wasting a lot of time and computation on playing thousands of games because that's the only way to find out what your changes did for you.

I think I should just skip late move reductions and prepare version 0.5 for a release... or maybe just call it 1.0 directly and declare MinimalChess done! Because by making these optimizations now that come at a price and skipping optimizations that have no downside other than the complexity they add to the code base it feels like I'm riding a dead horse! Like I missed the point where any reasonable person would say: "Based on the original vision of the project I'm done. This is minimal and simple and anything I add now will water down the purity of the original vision."

There's even a term for it. It's called Feature Creep!
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
amanjpro
Posts: 883
Joined: Sat Mar 13, 2021 1:47 am
Full name: Amanj Sherwany

Re: MCEC anyone?

Post by amanjpro »

lithander wrote: Mon Jun 14, 2021 8:44 pm
amanjpro wrote: Mon Jun 14, 2021 2:49 am I have been watching a few games of Minimal Chess, and while in the middle-game and early endgame he often outplays the opponent, no matter which engine it is. When it comes to the finish blow, due to the lack of TT, he often blows the win by not seeing deep enough.

TT really pays off in the ending, I would highly recommend it. It is an easy 100 elos or so
Thanks for the analysis and I think you're spot on. It would be the obvious next step to make the engine play stronger. I'm sure that most if not all engines playing above 2k ELO will have transposition tables.
mvanthoor wrote: Mon Jun 14, 2021 10:24 am Now you're having to decide if you build a TT into MinimalChess, or do a non-minimal rewrite.
That's exactly the thing. There are some basic design decisions like having a copy/make design instead of a make/unmake one that only make sense if the design goal is simplicity.
Transposition tables are all about gaining speed and playing strength not simplicity. So is it about speed now and climbing the ELO ladder? If I change my goal retroactively I should reconsider the design from the ground up. I should also stop writing idiomatic C# code because it's leaving a trail of millions of objects per second on the heap for the garbage collector to clean up. It's how the language is meant to be used but it's not exactly fast.

So, I feel like adding transposition tables now makes sense only if I forsake the goal of minimalism and simplicty. And then I should do a dozen other refactorings, too. And then we are not talking about MinimalChess anymore but something else.
mvanthoor wrote: Mon Jun 14, 2021 10:24 am This engine thing is never going to end... must have 5 more Elo... :twisted:
But is that fun to you? I don't think that's fun for me. Currently I'm trying to add late move reductions because that is a really simple idea and it can be done without adding much extra code. But there are so many variants that I could consider... what is considered a late move? how much do you reduce? And so on... And in every scenario you will pay a price for the additional search depth: Sometimes you'll miss a few good moves because the path to them didn't look too promising and got pruned. And so it remains a trade off even if it gains you a few ELO.

Also whether the tradeoff is a benefit in practice seems to depend a lot on the opponent and the time controls. So it feels like I'm making arbitrary changes that could or could not work and I won't know before i test it. So I'm wasting a lot of time and computation on playing thousands of games because that's the only way to find out what your changes did for you.

I think I should just skip late move reductions and prepare version 0.5 for a release... or maybe just call it 1.0 directly and declare MinimalChess done! Because by making these optimizations now that come at a price and skipping optimizations that have no downside other than the complexity they add to the code base it feels like I'm riding a dead horse! Like I missed the point where any reasonable person would say: "Based on the original vision of the project I'm done. This is minimal and simple and anything I add now will water down the purity of the original vision."

There's even a term for it. It's called Feature Creep!
I understand your worry, but it is also so heartbreaking to see this fine play gets rewarded with a loss! It is always easy to re-define the term minimal and address this feature to make your fans happy :P
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: MCEC anyone?

Post by mvanthoor »

lithander wrote: Mon Jun 14, 2021 8:44 pm That's exactly the thing. There are some basic design decisions like having a copy/make design instead of a make/unmake one that only make sense if the design goal is simplicity.
Transposition tables are all about gaining speed and playing strength not simplicity. So is it about speed now and climbing the ELO ladder? If I change my goal retroactively I should reconsider the design from the ground up. I should also stop writing idiomatic C# code because it's leaving a trail of millions of objects per second on the heap for the garbage collector to clean up. It's how the language is meant to be used but it's not exactly fast.
If it comes right down to it, even Rustic isn't completely idiomatic Rust. Even though Rust promises zero-cost abstractions, using the language everywhere in the engine as it was supposed to be used (like using enums for pieces and squares, not using "for" but an iterator to iterate over a list) is just cumbersome.

Sometimes, you need to know the exact piece, like "knight". An enum makes this super safe and convenient in Rust, because you can't mix up "knight" with "king" for example. (In a C enum you can, because they are just ints.) However, often you also need the numerical value of the enum, such as "1" for Queen, so you can use it to index an an array. In Rust, I'd need to write something that does this:

Code: Select all

array_here[Queen::value() as usize];
That gets tiresome very fast. So I just have an empty struct with a list of constants, which creates something akin to a C-enum, but namespaced, so I can do:

Code: Select all

array_here[Piece::QUEEN];
From a "good programming practice" point of view, this is bad, because you can swap the queen with a king, and the program doesn't complain and probably crash. (I can even swap pieces with squares... and the program won't complain and then crash.) Doing it the "proper" way though is so long-winded and cumbersome that it becomes unpractical (and needs conversions from enum to int and back, so it's probably slow as well).

Same with iterating through an array. You should be doing:

Code: Select all

for (i, x) in array_here.iter().enumerate() {
	...
}
But if you then hit a certain condition and want to stop the iteration, you'd have to break. I find "breaking" loops really ugly. (Back when I started programming, it wasn't even possible in Pascal, because it was considered ugly.) I prefer to write this:

Code: Select all

let i = 0
let condition = false;
while i < array_here.length() && !condition {
	...
	condition = ... (something that evaluates to a boolean here, obviously)
	i++;
}
Rust considers this "ugly", because you could forget to increase i, you need two extra variables, and you could forget to set the condition, so it's not idiomatic Rust. The correct way would be to use higher order functions such as "filter" in combination with iterators and closures, but often I find that to become completely unreadable. And, you need an object over which you can iterate. My move list is an array wrapped in a struct, backed by a counter, and it has push() and pop() methods. (Same for the history list, etc.) I could have used a vector, but the counter-backed array-in-a-struct is just over 10% faster, so I use that. I _could_ still use iterators, filter, and closures, but then I'd have to implement an iterator in the struct. That's extra work, an extra layer of abstraction, and because it emits references to the values in the array, it needs an extra indirection, which is probably slower than just looping over the array directly.

So yes... Rustic is more C-like in many places than I'd like, but it is just _faster_. In many places, I use Rust as a "better C". Maybe, at some point, I'll take a look into "idiomizing" the engine as much as possible, but only if it doesn't take a huge amount of extra code, and it doesn't cost any speed.
But is that fun to you? I don't think that's fun for me. Currently I'm trying to add late move reductions because that is a really simple idea and it can be done without adding much extra code. But there are so many variants that I could consider... what is considered a late move? how much do you reduce? And so on... And in every scenario you will pay a price for the additional search depth: Sometimes you'll miss a few good moves because the path to them didn't look too promising and got pruned. And so it remains a trade off even if it gains you a few ELO.
That was of course said in jest. Getting 5 more Elo is not fun for me. My goal is to get as much Elo out of each feature as I can before I move to the next feature. I want to create the strongest engine I can with the least amount of features. And, with good documentation and not in C.
I think I should just skip late move reductions and prepare version 0.5 for a release... or maybe just call it 1.0 directly and declare MinimalChess done!
If you want to have a good, idiomatic, around 2000 Elo chess engine in C#, then that would be a very good idea. Make a few more youtube video's, and call it a day on MinimalChess. It's a good contribution to the chess engine community, other people can use it as a base if they want to, they can learn some stuff from your video's, and you learned a lot as well.

Then redesign a new engine purely for speed and power, and reconsider if you want to write that in C#; you could write it in C++, C, or Rust... or even Ada, Pascal, or D if you want to go to niche languages just to avoid the mainstream.
Because by making these optimizations now that come at a price and skipping optimizations that have no downside other than the complexity they add to the code base it feels like I'm riding a dead horse! Like I missed the point where any reasonable person would say: "Based on the original vision of the project I'm done. This is minimal and simple and anything I add now will water down the purity of the original vision."
That's a completely understandable viewpoint. If your goal was a simple, idiomatic C# engine that plays decently, you've more than achieved that goal with a 2000+ rating. You're done with _this_ engine, but hopefully not with chess programming.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: MCEC anyone?

Post by hgm »

Having tapered eval seems a lot less minimal to me than having a transposition table.
amanjpro
Posts: 883
Joined: Sat Mar 13, 2021 1:47 am
Full name: Amanj Sherwany

Re: MCEC anyone?

Post by amanjpro »

We are in the last mile of the first season (test run) of ZaTour. I have another engine that will participate for next Season, I have also contacted Aryan (the author of Bit-Genie) if he wants to participate.

If anyone wants to participate, please register here: https://docs.google.com/forms/d/1podbnb ... -PnIdPObTU

For the second season, I'll also add ZuFi (ZaTour Super Final) between the winner and the runner up!
User avatar
lithander
Posts: 881
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: MCEC anyone?

Post by lithander »

hgm wrote: Mon Jun 14, 2021 10:43 pm Having tapered eval seems a lot less minimal to me than having a transposition table.
With just material values my engine didn't know where to put pieces. Once you have introduced the idea of making the value of a piece depend on it's square then it's just a few more steps to a tapered (do it twice, interpolate result), tuned (find better values through hill climbing) evaluation. I'm fairly sure I could still explain it all to a non-programmer.

I guess even terms like simple and minimal are pretty subjective. MinimalChess' interpretation is more like "easy to understand" while micro-Max is instead defining minimal as least amount of characters. The code however looks pretty obfuscated. Short but not at all simple.

But it doesn't change the fact that MMC is missing a transposition table badly and is losing endgames for the lack of it.
mvanthoor wrote: Mon Jun 14, 2021 10:24 pm If you want to have a good, idiomatic, around 2000 Elo chess engine in C#, then that would be a very good idea. Make a few more youtube video's, and call it a day on MinimalChess. It's a good contribution to the chess engine community, other people can use it as a base if they want to, they can learn some stuff from your video's, and you learned a lot as well.

Then redesign a new engine purely for speed and power, and reconsider if you want to write that in C#; you could write it in C++, C, or Rust... or even Ada, Pascal, or D if you want to go to niche languages just to avoid the mainstream.
I don't think it's the language that's holding me back. It's not even the lack of using best-practices like e.g. bitboards. At this point it's mostly that I've favored simplicity over performance whenever a decision had to be made. So, before I make such a radical change and start from scratch I'd be really curious to see what the engine would play like if it was a little more optimized for speed & strength. I'm just not sure if such an engine should still be called MinimalChess as it's already a bit of a stretch ;)
amanjpro wrote: Mon Jun 14, 2021 9:31 pm I understand your worry, but it is also so heartbreaking to see this fine play gets rewarded with a loss! It is always easy to re-define the term minimal and address this feature to make your fans happy :P
Sure, I could re-define the term 'minimal' (again) and add just one more feature.

Or I could make a new repository with a new name, copy the code over, unshackle myself from the pledge of writing something small and simple and start to optimize for speed instead. For a while it would probably still play the same way just faster. For a while it would still be fairly simple - just with a few hundred extra lines of optimizations.

But over time, unless I intentionally keep stuff like the 8x8 mailboard representation and the current move generator for the sake of originality, it would also become more and more similar to other engines in the 2000-3000 ELO range, feature wise. If you want to climb the ladder you gotta follow the best practices. Are the next few hundred ELO worth sacrificing my engines only USP?

What would the fans want me to do? ;) (I'm really undecided here... as you can see)
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
amanjpro
Posts: 883
Joined: Sat Mar 13, 2021 1:47 am
Full name: Amanj Sherwany

Re: MCEC anyone?

Post by amanjpro »

lithander wrote: Wed Jun 16, 2021 2:27 am
What would the fans want me to do? ;) (I'm really undecided here... as you can see)
The fans want a better MMC, they want TT and winning endgames :)
amanjpro
Posts: 883
Joined: Sat Mar 13, 2021 1:47 am
Full name: Amanj Sherwany

ZaTour: Submission for season 2

Post by amanjpro »

Now season 1 is wrapping up, if you want to participate in the next season (starting soon), or if you wish to change your binary, please register here:

https://docs.google.com/forms/d/1podbnb ... -PnIdPObTU

If you have already sent your binary, and do not want to change the binary for the next season, you don't need to re-register
User avatar
hgm
Posts: 27790
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: MCEC anyone?

Post by hgm »

lithander wrote: Wed Jun 16, 2021 2:27 amWith just material values my engine didn't know where to put pieces. Once you have introduced the idea of making the value of a piece depend on it's square then it's just a few more steps to a tapered (do it twice, interpolate result), tuned (find better values through hill climbing) evaluation. I'm fairly sure I could still explain it all to a non-programmer.
PST is indeed a trivial enhancement of having just material + centralization. But I would say tapering is just a small refinement, of which there would be dozens that would perhaps bring more playing strength. And I don't think the concept of a TT would even have to be explained to a non-programmer. Every chess player knows what a transposition is.
I guess even terms like simple and minimal are pretty subjective. MinimalChess' interpretation is more like "easy to understand" while micro-Max is instead defining minimal as least amount of characters. The code however looks pretty obfuscated. Short but not at all simple.
The goal of micro-Max was not simplicity but size. The number of characters was a nice exact and objective measure for that. "Ease of understanding" is much more difficult to quantify. And, as this discussion shows, much less objective.

Size and simplicity in the sense of dropping features that aren't very essential of course go hand in hand. Obfuscation is an aspects that has the opposit effect on size and ease of understanding, though. If you would take away the obfuscation, I think micro-Max' algorithm would be quite easy to understand, even the TT (which is implemented through just a hand full of statements). It is just a table in which it stores the result of each completed iteration of its Internal Iterative Deepning loop (i.e. score and move), so that when it encounters the same position again it can start with the first iteration that was not done before. (Which in the case of a true transposition, rather than a revisit in the next iteration, might lead to nothing having to be done at all.)