How strong should an engine be with various features implemented?

Discussion of chess software programming and technical issues.

Moderator: Ras

Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: How strong should an engine be with various features implemented?

Post by Henk »

If your engine is below 1800 Elo you better do woodcounting + small random value as a start.
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: How strong should an engine be with various features implemented?

Post by mvanthoor »

jmcd wrote: Fri Apr 17, 2020 8:37 pm
mvanthoor wrote: Fri Apr 17, 2020 8:14 pm
My suggestion would be to strip every feature from the engine, so you have only the bare-bones engine left, and then test it. After that, add each feature back in, testing them one by one.
I think this is what I will end up doing soon. Some features I feel I have implemented very cleanly, and some I am not proud of at all. I definitely have a better understanding of all the concepts I've used now than I did when I first wrote them.

I will be sure to follow your development as well!
I have also noted something else, after giving your code a very cursory scan. Please note that I'm pointing out a difference here, not making a judgement, because everybody has his or her own coding style.

Your engine has about 2250 lines of code, and no comments.
Of those 2250 lines, 1800 are in bot.cpp/hpp and board.cpp/hpp. Board.cpp is 1200 lines long. That is 80% of your engine, residing in two files.
It seems you have no testing features except for maybe perft (seems to be commented out... or they're in board.cpp for example; I said I only did a cursory scan).
Your engine has 62 commits.

If I compare that to my setup:
2150 lines of code, split over 33 files, none of which is longer than 200 lines. I have 500 lines of comments.
Of the 2150 lines, 720 are used for debugging and testing purposes (not all of those will end up in the final executable); so only 1430 lines are actually used for playing chess. (I haven't got a UCI-interface or even a search yet; one of them is due to be started this weekend.)
My engine has over 250 commits.

What I'm trying to say is:

If this is your first engine, you might be going too fast, too soon. You're changing huge chunks of codes (lots of lines per commit), without doing enough testing and refactoring. You have, for my taste, files that are becoming way too long to handle.

My advice would be to slow down. Copy your engine and put it somewhere. Strip everything out, down to the part where it only does Perft. Refactor everything and make it as consistent as possible. Test Perft, and post the speed you're reaching. On a i7-6700K, both Weiss (by Terje) and Rustic (by me) reach 36 million moves/sec (perft 7 in 88.xx seconds).

Our engines follow the exact same premise: fancy magic bitboards, full make/unmake to ply 0 in perft (no bulk counting), no hash table, no tricks in the move generator. Both seem to have no redundant or inefficient code in the move generator or perft function. C and Rust are both compiled languages and compile to roughly the same machine code (Rustic is compiled using rustc/LLVM while, Weiss is compiled using clang/LLVM or GCC).

The result is that they have EXACTLY the same speed +/- about 0.5 seconds fluctuations, which is exactly within expectation.

If I'd run your perft function on my machine and it runs at 200 seconds, the conclusion would be: it's slow. You start at a 50-70 ELO disadvantage before you even BEGIN to add features to play chess. If you run at 55 seconds (like Crafty on my system, which probably has a more sophisticated move generator than Weiss and Rustic, as it has been in development for a very long time), you start at a 50-70 ELO advantage before you begin adding features.

The point is: perft speed gives you a very good way to determine where your initial expectations could and should be. If your perft speed is three times as long as that of a similar engine, adding new features will obviously improve it, but the faster engine will improve MORE by adding the same feature.

If you want, I can send you a preliminary copy (compiled for your machine) of Rustic's perft routine. You can download and compile Weiss from Github.

After you know where your engine is starting out, then either improve the move generator / make / unmake to catch up if you're behind (I did, when I noticed I was like 40 seconds behind Weiss, even though we use the same techniques), or accept where you are now, and improve this later. This is your own choice. Then add in each feature one by one, keeping it consistent (naming, variable orders, commenting...) with what you have, until you have a bare-bones playing engine again. Establish a base ELO-rating. It doesn't matter if it turns out only to be 1200 ELO. Add features one by one, doing a thousand test games with a pool of other engines, and note down the new rating.

Rinse, repeat...

At least, that's how I'm going to do it.

The only thing I can say is that I've written all of my current code this way, testing function by function as I go, with only 2 bugs; and they weren't even really bugs but omissions of edge cases I've never encountered in an over the board game, so I didn't take into account to check them during make move.

As jdart said: If this is your first engine, focus on correctness first.

Don't fall into the trap of writing an engine with a gazillion features, and then ending up with 5.000 lines of unmaintainable, buggy code. That would be a waste of time and the waste of a chess engine, as you'd have to start over again to fix it.

PS: Yes, Rustic is my first chess engine as well, but I've been writing embedded software for almost two decades. That software has to be tiny, super-fast, it needs to live in a machine for maybe 10-20 years, and, sometimes, after not being touched for five years or longer, suddenly needs to be adapted, because a part in the machine is being replaced after a failure and the original part can't be obtained for whatever reason. In such a case, the program needs to be clear and maintainable. I'm writing this chess engine the same way; as if it is intended to last for 30 years with off-and-on development.
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: How strong should an engine be with various features implemented?

Post by mvanthoor »

Oh, by the way.... what's the name of this new creature?

Calling it "chess engine" might be somewhat ambiguous.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: How strong should an engine be with various features implemented?

Post by Henk »

mvanthoor wrote: Fri Apr 17, 2020 9:51 pm Oh, by the way.... what's the name of this new creature?

Calling it "chess engine" might be somewhat ambiguous.
Good names for chess engines are names like nightmare, deathwish or heroin.
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: How strong should an engine be with various features implemented?

Post by mvanthoor »

Henk wrote: Fri Apr 17, 2020 10:30 pm Good names for chess engines are names like nightmare, deathwish or heroin.
Nightmare and Knightmare both already exist.
Deathwish if a good name if you start a new chess engine in C in 2020 :lol:

(Just kidding :P )
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
jmcd
Posts: 58
Joined: Wed Mar 18, 2020 10:00 pm
Full name: Jonathan McDermid

Re: How strong should an engine be with various features implemented?

Post by jmcd »

mvanthoor wrote: Fri Apr 17, 2020 9:37 pm
Your engine has about 2250 lines of code, and no comments.
Of those 2250 lines, 1800 are in bot.cpp/hpp and board.cpp/hpp. Board.cpp is 1200 lines long. That is 80% of your engine, residing in two files.
It seems you have no testing features except for maybe perft (seems to be commented out... or they're in board.cpp for example; I said I only did a cursory scan).
Your engine has 62 commits.
Thanks for the criticisms. I am in exam season right now and will be giving your points more thought later, but I'd like to address this now as it is a nagging thought that I've already had.

The length of bot.cpp and board.cpp is a result of see and the splitting of move generation into 3 functions (gen all moves, gen captures, gen non captures). After reading the mediocre chess blog, he states that saving work that doesnt need to be done until it absolutely does is effective, and it improved my engine when I implemented it. If i remove the reduncancy, the see method is slower (because the work can be done in the standard move generation), and the engine generates moves that likely wont be used, but bot.cpp is now 400 lines, and board.cpp is now 800 lines. The engine is cleaner, but slower. Is it really worth it to remove the redundancy?

As for comments, yes I definitely need to add more.
Clovis GitHub
Dann Corbit
Posts: 12816
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: How strong should an engine be with various features implemented?

Post by Dann Corbit »

Best names for an engine are quirky and unassuming,
witness: Stockfish, Fruit, Yace, Fizbo, Booot, Arasan, Gull.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
Dann Corbit
Posts: 12816
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: How strong should an engine be with various features implemented?

Post by Dann Corbit »

jmcd wrote: Fri Apr 17, 2020 10:45 pm {snip}
The length of bot.cpp and board.cpp is a result of see and the splitting of move generation into 3 functions (gen all moves, gen captures, gen non captures). After reading the mediocre chess blog, he states that saving work that doesnt need to be done until it absolutely does is effective, and it improved my engine when I implemented it. If i remove the reduncancy, the see method is slower (because the work can be done in the standard move generation), and the engine generates moves that likely wont be used, but bot.cpp is now 400 lines, and board.cpp is now 800 lines. The engine is cleaner, but slower. Is it really worth it to remove the redundancy?

As for comments, yes I definitely need to add more.
Now is not the time to worry about fast. Your goals should be:
1. Correctness. Read the source of Fruit for a tutorial on how to do this
2. Clarity. Make it easy to read and understand. Limit the jobs of a single function to exactly one function.
3. Robustness - aim for code that can handle surprises

After a super simple chess program implements those things, use the same principles to improve it.
If you want to make your program faster, quirky things like inlining all the code or splotches of assembly are a last resort and generally not a good idea,
Instead, find a better algorithm. Don't use a tree when you can use a hash, aim for good big-O properties but ONLY AFTER you have correct code and you have verified that the code you are trying to improve is the bottleneck with a profiler.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
Dann Corbit
Posts: 12816
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: How strong should an engine be with various features implemented?

Post by Dann Corbit »

One minor point - malloc and new are not your friends in a chess program, so use dynamic allocation when needed but not willy-nilly. Beware of data structures that do lots of memory allocation for you, because this is expensive in a chess program.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: How strong should an engine be with various features implemented?

Post by Henk »

mvanthoor wrote: Fri Apr 17, 2020 10:36 pm
Henk wrote: Fri Apr 17, 2020 10:30 pm Good names for chess engines are names like nightmare, deathwish or heroin.
Nightmare and Knightmare both already exist.
Deathwish if a good name if you start a new chess engine in C in 2020 :lol:

(Just kidding :P )
If it uses bitboards and programmer starts debugging one can call it Deathwish II