In the previous article, we saw a simple way to represent the board and associated details in memory. Now, we’ll deal with move playing and generation. Specifically, this time, we’ll only deal with slider moves.

Chess pieces can be classified as sliders and leapers. For example, rooks and bishops are sliders whereas the knight is a leaper. Hence, while generating moves, we need a loop for stepping multiple squares for bishops, rooks and queen(s) whereas a single step for a knight(for a pawn or a king as well).

If that makes no sense, take a look at the code snippet below(full code here):

var_i = i + 1;
var_j = j + 1;
while(is_square_in_range(var_i, var_j)) {
    next_piece = board[var_i][var_j];
    if(get_piece_side(next_piece) == opposite_side()) {
      movelist.push_back(move({i, j}, {var_i, var_j}, next_piece));
      break;
    } else if(get_piece_side(next_piece) == BLANK) {
        movelist.push_back(move({i, j}, {var_i, var_j}));
        var_i++;
        var_j++;
    } else {
        break;
    }                           
}

Here the variables i(row) and j(column) represent the square of the piece for which we are generating the move. The is_square_in_range function tells us if the row and column are valid with respect to our chessboard. i.e. the 8×8 array. Both indices must fall between 0 and 8.

var_i and var_j are the variables representing the square where our piece is moving. Notice how they are both incremented by one. This causes it to move in the lower right corner as per our array numbering. Take a look below to understand this. The black bishop at (2, 3) will move along the lower right direction(the path marked XX) if we continue to increment both its indices at once.

    0  1  2  3  4  5  6  7
0  -- -- -- -- -- -- -- --                          
1  -- -- -- -- -- -- -- --           
2  -- -- -- BB -- -- -- --                      
3  -- -- -- -- XX -- -- --                              
4  -- -- -- -- -- XX -- -- 
5  -- -- -- -- -- -- XX --
6  -- -- -- -- -- -- -- XX          
7  -- -- -- -- -- -- -- --

The below code snippet generates a move if the square is empty and then increments the indices.

else if(get_piece_side(next_piece) == BLANK) {
        movelist.push_back(move({i, j}, {var_i, var_j}));
        var_i++;
        var_j++;
}

The first if block generates a move to capture an enemy piece if present and then breaks out of the loop(since we cannot get beyond this anyway). To illustrate:

    0  1  2  3  4  5  6  7
0  -- -- -- -- -- -- -- --                          
1  -- -- -- -- -- -- -- --           
2  -- -- -- BB -- -- -- --                      
3  -- -- -- -- WP -- -- --                              
4  -- -- -- -- -- -- -- -- 
5  -- -- -- -- -- -- -- --
6  -- -- -- -- -- -- -- --          
7  -- -- -- -- -- -- -- --

Here the bishop can only make two moves, go to (3, 4) or capture the pawn at (4, 5).

Finally, the slider can be blocked by a piece of its own color, like the example below where the black bishop is blocked by the black queen. We break out of the loop in this case as well.

    0  1  2  3  4  5  6  7
0  -- -- -- -- -- -- -- --                          
1  -- -- -- -- -- -- -- --           
2  -- -- -- BB -- -- -- --                      
3  -- -- -- -- BQ -- -- --                              
4  -- -- -- -- -- -- -- -- 
5  -- -- -- -- -- -- -- --
6  -- -- -- -- -- -- -- --          
7  -- -- -- -- -- -- -- --

That’s it :-). We have just reviewed the basic skeleton for slider move generation. To generate the moves for the rest of the diagonals; we just initialize var_i and var_j in different ways. Here i and j are the coordinates of the piece we are moving.

var_ivar_j
Lower rightInitial Value: i + 1
Increment by 1 per loop
Initial Value: j + 1
Increment by 1 per loop
Lower leftInitial value: i + 1
Increment by 1 per loop
Initial value: j – 1
Decrement by 1 per loop
Upper RightInitial value: i – 1
Decrement by 1 per loop
Initial Value: j + 1
Increment by 1 per loop
Upper LeftInitial value: i – 1
Decrement by 1 per loop
Initial value: j – 1
Decrement by 1 per loop

Similarly, for straight moves(which will be generated for rooks and queens), we have the following. But wait, both these tables only hold true for the way we have represented the board. The initial values and increments/decrements may change on how you choose to implement it.

var_ivar_j
RightInitial Value: i
Keep fixed
Initial Value: j + 1
Increment by 1 per loop
LeftInitial value: i
Keep fixed
Initial value: j – 1
Decrement by 1 per loop
UpInitial value: i – 1
Decrement by 1 per loop
Initial Value: j
Keep fixed
DownInitial value: i + 1
Increment by 1 per loop
Initial value: j
Keep fixed

Take a look at the code here to see the implementation of all the above, as well as some of the auxiliary functions we have used.

Since we haven’t implemented a FEN or PGN parser yet, I have created a sample board in which the pawn in front of the queen is absent(just to see which moves are generated). FEN and PGN are ways to represent a position in chess. Here is the output( a total of 11 moves are possible):

BR BN BB BQ BK BB BN BR 
BP BP BP BP BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
WP WP WP -- WP WP WP WP 
WR WN WB WQ WK WB WN WR 

Side to play: WHITE

Total possible moves: 11

BR BN BB BQ BK BB BN BR 
BP BP BP BP BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
WP WP WP WB WP WP WP WP 
WR WN -- WQ WK WB WN WR 

Side to play: BLACK

BR BN BB BQ BK BB BN BR 
BP BP BP BP BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- WB -- -- -- 
WP WP WP -- WP WP WP WP 
WR WN -- WQ WK WB WN WR 

Side to play: BLACK

...(skipped the rest)...

BR BN BB BQ BK BB BN BR 
BP BP BP BP BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
WP WP WP WQ WP WP WP WP 
WR WN WB -- WK WB WN WR 

Side to play: BLACK

BR BN BB BQ BK BB BN BR 
BP BP BP BP BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- WQ -- -- -- -- 
WP WP WP -- WP WP WP WP 
WR WN WB -- WK WB WN WR 

Side to play: BLACK

...(skipped the rest)...

BR BN BB BQ BK BB BN BR 
BP BP BP WQ BP BP BP BP 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
-- -- -- -- -- -- -- -- 
WP WP WP -- WP WP WP WP 
WR WN WB -- WK WB WN WR 

Side to play: BLACK

....

That’s it for this article. Next time, we will see how to generate moves for knights, the king and pawns(including tricky maneuvers like en passant. See you soon!

Advertisements

About the Author Pranav Deshpande

Software Developer interested in AI, Reinforcement Learning and game programming.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s