Dann Corbit wrote:If there are variables needed only in a single file, they should not be put into any include file. It is clearly a mistake to do it in that case.
Sure! Perhaps Uri is also thinking of the typical "Crafty-layout" with all (global) data in one file. And of course one include file, with all those "extern ..." declarations.
IMHO, it is not trivial, to make a chess engine rather modular. It is not difficult either, but may be lots of work.
Once, I thought to have a seperate "book utiltities" program, for generating the opening book, adding moves to it, and more such things. Sounds easy - but I soon came to the conclusion that is (by a huge margine) too much work. I won't doubt, that with more disciplined programming, it should be easy. What was the case here: book generation code must read PGN. PGN reading code needs a move generator. For storing games in "internal format", I reuse structures actually used in searching. While generating the book, I want to give some progress indicators. These must be displayed. At some time, I was too lazy, to communicate all things that have to be displayed to the actual display routines (say middle level display routines - something like show_pv()). Instead, they will use some global vars like the node counter, all sorts of counters about hash statistics, TB accesses, the current position, .... . It turns out, that I practically would need functions from every module of my program.
I believe, I am aware, how to fix all this, and really make things modular in practice. I fear it comes with a rather high prize (for a hobby programmer). Instead of just adding a new variable unsigned long new_counter in some C and some header file, and just adding "... %lu ..." to some printing code, some new_counter=0 probably at the start of the search, and some new_counter++ at some appropriate place, you would additionally need to pass down this new_counter to many functions. (Classes and inheritance may help, to do it behind the scenes). For the hobbyist, that want's to try something new fast (inside an older, and probably not too well thought through design), just adding a global var will be much easier. The size of the typical chess engine might be just small enough, that such programming will work.
OTOH: after a while I saw, that what I thought of ages ago was a nice and clear design, basically becomes broken. Too many dependencies between different modules/variable are visable. When you work on the code on a daily basis, a chess engine will still be small enough - and all the programmer can be very efficient. When you visit your code after some weeks or months again, you easily forget about some dependencies, and my have a hard time.
Certainly, many have designed their engines better than me. One little challenge: How long would you need, to write a standalone program (with more or less minimal code), that can do a simple task, like reading a PGN and write a score sheet in coordinate notation? When I can use all of the engines framework, I am conficent I can do it in 15 minutes (I would add a command to yace - something like convert_pgn_to_coordinate input.pgn output.txt). For a stand-alone program, that would not include most code of the engine (but could use any code, it wants), it probably would take several days. To clarify the challenge: use as much code as you want, that you already have written. But don't use too much (one or the other routine included, that will never be called will not matter) of it, or even all the code in your engine.
What I have in mind: Can do it in a way like this?
I write a routine, that outputs a game in coordinate notation
I add some user interface to call this
I need PGN parsing module
I need move generator
I need basic input output routines
... some more
I don't need my search module
I don't need my eval module
....
Of those modules I need, I just throw out many things.
Regards,
Dieter