# Pawn Pushes (Bitboards)

**Home * Board Representation * Bitboards * Pawn Pattern and Properties * Pawn Pushes**

Bitboards allow to determine pawn push target squares, or equivalently their stop squares set-wise, while pawn pushes of a single pawn are the domain of mailbox-approaches. To generate the single-step targets for all pawns requires vertical shift by one rank and intersection with the set of empty squares. The resulting set might be shifted one more time for the double pushes by further intersection with empty squares on the fourth (white) or fifth (black) double push target ranks. Since double pushing triggers determination of en passant target square, it makes sense to serialize both sets separately for different move encoding.

# Push per Side

Keeping different but most efficient code for both white and black pawns. The code snippets rely on shifting bitboards, specially by one step only.

U64 wSinglePushTargets(U64 wpawns, U64 empty) { return nortOne(wpawns) & empty; } U64 wDblPushTargets(U64 wpawns, U64 empty) { const U64 rank4 = C64(0x00000000FF000000); U64 singlePushs = wSinglePushTargets(wpawns, empty); return nortOne(singlePushs) & empty & rank4; } U64 bSinglePushTargets(U64 bpawns, U64 empty) { return soutOne(bpawns) & empty; } U64 bDoublePushTargets(U64 bpawns, U64 empty) { const U64 rank5 = C64(0x000000FF00000000); U64 singlePushs = bSinglePushTargets(bpawns, empty); return soutOne(singlePushs) & empty & rank5; }

# Pawns able to Push

To get the set of source squares of pawns able to push is about intersection of pawns with the shifted empty squares in opposite direction:

U64 wPawnsAble2Push(U64 wpawns, U64 empty) { return soutOne(empty) & wpawns; } U64 wPawnsAble2DblPush(U64 wpawns, U64 empty) { const U64 rank4 = C64(0x00000000FF000000); U64 emptyRank3 = soutOne(empty & rank4) & empty; return wPawnsAble2Push(wpawns, emptyRank3); }

and similar for black.

# Generalized Push

One may rely on the generalized shift for one color parametrized pawn push routine. Since pawns don't occur on the first or eighth rank, one may either safe the wrap-ands ...

enum { white, black }; U64 singlePushTargets(U64 pawns, U64 empty, int color) { return rotateLeft( pawns, 8 - (color << 4) ) & empty;; }

... or make the "white" north-shift unconditionally but to conditionally shift back south two ranks by color*16:

U64 singlePushTargets(U64 pawns, U64 empty, int color) { return ( (pawns << 8) >> (color << 4) ) & empty; }

# Forum Posts

- How to Shift Left (by) a Negative Number?? by Steve Maughan, CCC, April 05, 2013