Steve Maughan wrote:I have both. The beauty of C is you can have a single piece list which is viewed either as board->pieces[color][type] or board->piecelist[piecetype]. Take a look at my "board.cpp" and "defs.h" files at
Chess Programming.
Steve
This representation is redundant, which is error prone (and potentially inefficient though negligibly so). How do you ensure that the board invariant are always respected ? In DiscoCheck, I simply use something like:
Code: Select all
uint64_t by_color[2], by_piece[6];
For example black knights are given by something like
Code: Select all
by_color[BLACK] & by_piece[KNIGHT]
obviously you wrap that into (inlined) functions to access all you need by staying high level.
Another advice I can give is to write two functions:
- set_square(): put a given piece of a given color on a given square. assert() that the square is empty first, that the piece, square and color arguments are correct.
- clear_square(): empties a given square. assert() that the square was indeed occupied.
These functions should modify all there is to modify: the bitboard representation (the 2 arrays mentionned above), as well as the zobrist key, PSQT sums and whatever else you may need to compute dynamically.
No other code should *ever* touch the board representation directly. If these functions are correct and maintain the board invariants, you know that anything that screws up the board is going to trigger an assert() squeel in these two functions. And you know you're not going to screw things up because you basically cannot, so long as you never manipulate the board structure directly. Use some accessors for whatever you may need to access.
This abstraction is fundamental and has saved me countless hours of debugging pain and tears. You can trust my advice on this.
As an optimisation you can use a stack and put some dynamically computed on the stack. You'll need a stack for undo information anyway. This means you only really do calculation when you make a move, and undo_move() simply shifts the stack pointer. That was a nice speed gain at the time when I was very competitive about my perft() raw speed. At the scale of a polished engine with lots of other things to calculate, these meager optimizations are drops in the ocean though.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.