1/29/2013

Moving pieces

An efficient move generator is an essential part of a strong chess engine. The rules of chess determine the movement of different pieces. Most pieces move quite nicely, but there are expections which make the implementation of a move generator more difficult than it would be without them. The purpose of this post is to examine how to pieces move and how to implement a generic move generator.

But first, it is appropriate to mention here that it is not always necessary to generate all moves for all positions during the search. Many chess engines do this, while others generate the moves in stages like: checks, captures, other moves. If the search fails high after a move, it is not necessary to go through all the rest of the moves and the effort used when generating them is wasted. On the other hand, generating one move at a time will probably be difficult and add extra instructions. However, in zero window search, it can be so that only one move is searched at every other ply. It would be possible to use separate move generation routines for every other ply then. But for simplicity, we try to construct a generic move generator.

It would be nice to have a move generator without branching. This is difficult, but I think it can be done. If the branching cannot be avoided, the threads inside a warp will have to execute all the branches in many cases. Some of the benefits of parallellism are then lost. So we try to replace ifs with table lookups. That is why we need to see if the piece movement can be generalized. The following table lists some properties of the pieces:

PieceSlidingDirectionsMax. movesSpecialities
PawnNo34Capture and non-capture different, promotion, double move, en passant
KnightNo88
BishopYes413
RookYes414Castling
QueenYes827
KingNo88Castling, checks

So basically, pawns are the nastiest pieces and kings are also bad. Majority of the problems with the kings can be avoided by loosening the requirements. Checks can be handled separately and not as a part of move generation.

Generic move rules could consist of the piece to move, change in the board index (= direction), maximum steps it can "slide" (this equals one for non-sliding pieces), a condition for the move to be valid, and an extra action to take in addition to moving the piece. This leads to a table like:

PieceDirectionMax. stepsConditionAction
Pawn-81Destination square empty
Pawn-161Only 2nd row pawn, destination square and middle square emptySet EP square
Pawn-71Destination square occupied by enemy piece or EP square
Pawn-91Destination square occupied by enemy piece or EP square
Pawn-817th row pawn, destination square emptyChange to knight
Pawn-817th row pawn, destination square emptyChange to bishop
Pawn-817th row pawn, destination square emptyChange to rook
Pawn-817th row pawn, destination square emptyChange to queen
Pawn-717th row pawn, destination square occupied by enemy pieceChange to knight
Pawn-717th row pawn, destination square occupied by enemy pieceChange to bishop
Pawn-717th row pawn, destination square occupied by enemy pieceChange to rook
Pawn-717th row pawn, destination square occupied by enemy pieceChange to queen
Pawn-917th row pawn, destination square occupied by enemy pieceChange to knight
Pawn-917th row pawn, destination square occupied by enemy pieceChange to bishop
Pawn-917th row pawn, destination square occupied by enemy pieceChange to rook
Pawn-917th row pawn, destination square occupied by enemy pieceChange to queen
Knight-171
Knight-151
Knight-101
Knight-61
Knight61
Knight101
Knight151
Knight171
Bishop-97
Bishop-77
Bishop77
Bishop97
Rook-87Clear a castling flag
Rook-17Clear a castling flag
Rook17Clear a castling flag
Rook87Clear a castling flag
Queen-97
Queen-87
Queen-77
Queen-17
Queen17
Queen77
Queen87
Queen97
King-91Clear castling flags
King-81Clear castling flags
King-71Clear castling flags
King-11Clear castling flags
King11Clear castling flags
King71Clear castling flags
King81Clear castling flags
King91Clear castling flags
King-21Long castling allowedClear castling flags, move rook
King21Short castling allowedClear castling flags, move rook

The moves could be generated by look ups to such a table. In addition, it is required that the destination square is not off the board. Implementing the conditions is the hard part. Usually they can be formulated as tests if certain bits are set. The actions in the table can be seen as removing one piece and adding another piece.

To avoid ifs in the control flow, a move can be made so that if the condition is false, the move has no effect on any variable. Otherwise the move is made and the appropriate variables are updated. When returning from the search, the move is undone, and the execution continues from the next move at the previous level. The return pointer is then actually an index to the move generation table.

All this might sound confusing, but to avoid branching, I think this is necessary.

No comments:

Post a Comment