Move Generation: Move generation for pieces (other than pawns) is done using look up arrays.
Mailbox method is used and move generation is done using nested loops.
Code is easy to understand and self explanatory now.
Refer board.c
1. void gen() -
There is first a loop which goes through all the 64 squares to search for the pieces which belong to the side_to_move
for (i = 0; i < 64; ++i)
if (color[i] == side) {
Then pawn moves are handled separately.
En-passant is handled separately and not included in the regular pawn move block.
if (piece[i] == PAWN) {
if (side == LIGHT) {
if (COL(i) != 0 && color[i - 9] == DARK)
gen_push(i, i - 9, 17);
if (COL(i) != 7 && color[i - 7] == DARK)
gen_push(i, i - 7, 17);
if (color[i - 8] == EMPTY) {
gen_push(i, i - 8, 16);
if (i >= 48 && color[i - 16] == EMPTY)
gen_push(i, i - 16, 24);
}
}
else {
if (COL(i) != 0 && color[i + 7] == LIGHT)
gen_push(i, i + 7, 17);
if (COL(i) != 7 && color[i + 9] == LIGHT)
gen_push(i, i + 9, 17);
if (color[i + 8] == EMPTY) {
gen_push(i, i + 8, 16);
if (i <= 15 && color[i + 16] == EMPTY)
gen_push(i, i + 16, 24);
}
}
}
Notice that pawn moves are handled separately for different sides.
Because a white pawn will always move up the board and the black pawn will always move down the board.
Pawn double push is also handled.
For captures, if a white pawn is on the 'a' file then it cannot capture on the left.
Even, such things are handled.
Then moves for chess pieces is generated.
Nested loops are used.
The outer loop is for number of directions and inner loop is for sliders having more than 1 move in the same direction.
If edge of board is encountered or if pieces cannot go in that direction any further or if the piece is not a slider then the inner loop breaks.
The same order is important. Slider is the last thing to check because even if a piece is not a slider, atleast 1 move in a particular direction needs to be generated.
for (j = 0; j < offsets[piece[i]]; ++j)
for (n = i;;) {
n = mailbox[mailbox64[n] + offset[piece[i]][j]];
if (n == -1)/*Edge of board*/
break;
if (color[n] != EMPTY) { /*Piece cannot go further in the same direction.*/
if (color[n] == xside)
gen_push(i, n, 1);
break;
}
gen_push(i, n, 0);
if (!slide[piece[i]]) /*Piece not slider*/
break;
}
Finally castling and en-passant moves are generated.
Castling move is generated if the castle flag is set and en-passant is generated if en-passant flag is set.
Other rules would be checked by the makemove function.
2. void gen_push(int from, int to, int bits) -
This function does 3 things:
It takes the from square, to square and move_type from gen and pushes on the move list.
It updates the counter of the move list
It checks whether the move is of type pawn promotion. Then it does not do any of the above tasks and calls gen_promote() to do the same.
(Currently the score update can be ignored)
3. void gen_promote(int from, int to, int bits) -
It does the same thing what gen_push does but only for pawn promotions.
It also updates the move_type to a pawn promotion.
I have added code to give details of what is happening.
My suggestion is to use printf's wherever its unclear