Skip to content

Pawn moves generation

Sebastian Veile edited this page Jul 2, 2023 · 5 revisions

This page contains descriptions of the general logic behind finding possible moves for pawns using bitboards.

Prerequisites to follow along:

A white pawn has 4 possible moves that it can make initially:

       2
    3  1  4
       P

It can move 1 or 2 steps forward as well as an attack on the diagonal left or right. Moving forward requires there to be no opponent or own pieces in front of it. If the pawn has already moved once, it can no longer move two squares forward per move. Attacking on the diagonal requires that an opponent piece is placed on that diagonal.

It can be summed up to these 4 moves:

  • Single-push
  • Double-push
  • Diagonal left attack
  • Diagonal right attack

In the pawn-bitboard below, we want to simulate all its possible moves. We do so by setting the bit at every possible move position from the pawns current position.

White pawn bitboard (Current)
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  0  0
3  0  0  0  1  0  0  0  0
2  0  1  0  0  0  0  1  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H

Finding Possible moves

Since there are 4 possible pawn moves these moves can basically be generated with 4 bitshift operations.

Single-push

To generate the pawn moving one step forward, we can bitshift the pawn bitboard 8 to the left. (Pawn-bitboard << 8) We also need to make sure there are currently no other pieces blocking this square. - (Pawn-bitboard << 8) & empty-squares

(Pawn-bitboard << 8) empty-squares Single-push
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  1  0  0  0  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  0  0  0  0  0  0  0  0
7  0  1  1  0  0  0  0  0
6  1  1  1  1  1  1  1  1
5  1  1  1  1  1  1  1  1
4  1  0  1  1  1  1  1  1
3  1  1  0  0  1  1  1  1
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  1  0  0  0  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H

Double-push

Generating double-push is not as simple as bit-shifting by 16. If we only bitshift 16, we do not account for a blocking piece on the square right in front. Therefore the possibility of moving two steps is dependent on if single-push is possible. If so we can bitshift an additional 8 bits to the left (single-push << 8).
Double-move is only possible if the pawn is located on its initial square. To account for this we can check if the result of single-push is on rank 3 ((single-push & rank3) << 8).
To also account for possible blocking pieces we use bit-wise on empty-squares ((Single-push & Rank-3) << 8) & Empty-squares.

Single-push Rank3 (Single-push & Rank3)
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  1  0  0  0  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  0  0
3  1  1  1  1  1  1  1  1
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  0  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
((Single-push & Rank3) << 8) Empty-squares Double-push
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  1  0  0  0  0  1  0
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  0  0  0  0  0  0  0  0
7  0  1  1  0  0  0  0  0
6  1  1  1  1  1  1  1  1
5  1  1  1  1  1  1  1  1
4  1  0  1  1  1  1  1  1
3  1  1  0  0  1  1  1  1
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  1  0
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H

Diagonal left attack

Generating left diagonal attack is very similar to single push. Instead of bitshifting 8 to the left, we instead bitshift by 9. (Pawn-bitboard << 9) This simmulates the piece has moved one square up and left. Then we also need to take into account if an opponent piece is already there. ((Pawn-bitboard << 9)& Opponent-pieces) We cannot attack if there is no opponent piece.

White pawn bitboard (Current) Opponent-pieces (Current)
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  0  0
3  0  0  0  1  0  0  0  0
2  1  1  0  0  0  0  1  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
8  1  1  1  1  1  1  1  1
7  1  0  0  1  0  1  1  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  1  0  0  1
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
(Pawn bitboard << 9) Opponent-pieces ((Pawn Bitboard << 9) & Opponent-pieces)
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  0  0  0  1
3  1  0  0  0  0  1  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  1  1  1  1  1  1  1  1
7  1  0  0  1  0  1  1  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  1  0  0  1
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  0  0  0  1
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
In the resulting bit board above you can see all possible attacking moves on the left diagonal. However there is a problem. The pawn on A2 is able to attack a piece on H4. This is not supposed to happen. It happens because we bitshift 9 spaces to the left and since there are squares to diagonal left of A2, we end up on H4. To prevent this from happening we can use a "not-H-file" bitboard. This is a bitboard filled with 1's except for in the H file. Since diagonal left can never have an attack occour on the H file, we can use the bitwise and operator to remove all those moves. ((Pawn bitboard << 9) & not-H-file)
(Pawn bitboard << 9) not-H-file Opponent pieces Left diagonal attacks
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  0  0  0  1
3  1  0  0  0  0  1  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  1  1  1  1  1  1  1  0
7  1  1  1  1  1  1  1  0
6  1  1  1  1  1  1  1  0
5  1  1  1  1  1  1  1  0
4  1  1  1  1  1  1  1  0
3  1  1  1  1  1  1  1  0
2  1  1  1  1  1  1  1  0
1  1  1  1  1  1  1  1  0
   A  B  C  D  E  D  G  H
&
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  1  0  0  1
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  0  0  0  0
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H

Diagonal right attack

Diagonal right is very similar to diagonal left. The only difference is that here we bitshift by 7 (Pawn bitboard << 7). We also have to be aware of pawns on the H file this time. A pawn on the H file has no diagonal to its right, we therefore have to make use of a not-A-file bitboard similar to not-H-file bitboard used above. We then end up with the following operation ((Pawn bitboard << 9) & not-A-file & Opponent pieces)

(Pawn bitboard << 7) not-A-file Opponent pieces Right diagonal attacks
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  1  0  0  0
3  0  1  1  0  0  0  0  1
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
&
8  0  1  1  1  1  1  1  1
7  0  1  1  1  1  1  1  1
6  0  1  1  1  1  1  1  1
5  0  1  1  1  1  1  1  1
4  0  1  1  1  1  1  1  1
3  0  1  1  1  1  1  1  1
2  0  1  1  1  1  1  1  1
1  0  1  1  1  1  1  1  1
   A  B  C  D  E  D  G  H
&
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  1  0  0  1
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  1  0  0  0
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H

En passant

TODO

Final board

Now we've calculated all possible pawn moves. We can now use the bitwise or operator to combine all moves into one bitboard: For black pawns the same rules apply, its just the opposite. If you want to simulate moving one piece, you instead have bitshift 8 to the right and so on.

Single push Double push Left diagonal attacks Right diagonal attacks White pawn moves
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  1  0  0  0  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
|
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  1  0
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
|
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  0  0  0  0  0
3  0  0  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
|
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  0  0  1  0  0  0
3  0  1  0  0  0  0  0  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H
=
8  0  0  0  0  0  0  0  0
7  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0
5  0  0  0  0  0  0  0  0
4  0  0  1  1  1  0  1  0
3  0  1  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0
1  0  0  0  0  0  0  0  0
   A  B  C  D  E  D  G  H


Clone this wiki locally