I don't feel that anyone is trying to pile on me, but I must admit that I am surprised my little remark caused so many replies.
Being a non-programmer, I am not sure how the terms "top-down" and "bottom-up" are generally understood in programming, but both of them make some sense when describing my approach: The program is designed from the top down, but if one wants to write and test the code piece by piece, it would probably be most practical to do this from the bottom up. I usually don't write and test code this way, though. More about this below.
bob wrote:I agree with how you think it ought to be developed, but your definition of "top down" is simply backward. In a classic top-down design, you write the main program. For every procedure you want to call, you write a dummy (aka a "stub") that does nothing. You then get the main program to function as intended. Then you take the layer of stubs right below the main program and you start to flesh those in. But whatever procedure you call you do not write, you just supply a stub. But now you are one layer deeper into the design and the code is getting more specific. You continue this until you reach what we would call the "tips" in a tree search. This is where the real work is done, and this is where it is necessary for all the basic data structures to be finalized.
I don't recall ever having written such stub functions, but the approach you describe resembles a technique I often use in Lisp (the language I use in my day job). Lisp allows me to compile and run code which calls undefined functions (the compiler will emit a warning, though). I often do this intentionally. When the undefined function gets called, the program enters a break loop where I can choose between several actions, including manually supplying a return value for the undefined function, selecting some other function to call instead, or defining the function before continuing.
When writing a chess engine in C, I do it differently: I write the entire program (in top-down style) on paper before I type a single line of code at the computer. I don't start typing the code before I'm 100% sure the program is correct (which, of course, it never quite is, even though I am 100% sure). When everything is ready, I need a day or two typing everything and fixing all the silly little errors that have crept in everywhere. I write everything at once, rather than one little piece at the time. This is boring work, but it doesn't take a lot of time, and at the end I have a complete, working, stable and clean-looking chess engine.
Previously, I used to work more like most other participants in this thread seems to do. I started writing a board representation, a move generator (without "advanced" stuff like castling or promotions at first), an SEE function, and so on, and tested each of them with a few ad-hoc, non-rigorous tests. As I proceeded to more and more high-level parts of the program, I invariably found that the low-level parts didn't fit together as well as I had hoped, and I had to throw in ugly little hacks everywhere to make things work as intended.
Moreover, there were always bugs. Segmentation faults, non-terminating loops, pieces which suddenly changed color for no good reason, search bugs, hash table bugs, mysterious non-reproducible losses on time with ponder on, and so on. I spent countless hours in the debugger, or inserting output commands everywhere in the code to find out why something didn't work as intended. I usually managed to fix the problems, but the process was unbearably painful, and the code looked more and more messy.
In the end, I decided that life is just too short to debug C/C++ code. The endless edit-compile-test-debug cycle is sheer torture. I only write code I
know is correct, and the easiest achieve this is working top-down. It requires some mental discipline, but I end up with much cleaner code. Even more importantly, working with pencil and paper in a park or café is infinitely preferable to sitting in front of a computer and staring at a debugger.
Matt has a point, though: This style of working really only works when you already have a good understanding of the problem domain. If I were a beginner wanting to start chess programming, I would have started out with a more interactive programming language, and consider switching to C/C++ only when I had a satisfactory prototype.
Vincent also makes a good point: I am a mathematician, not a programmer, and this certainly has an impact on how I prefer to work.
Tord