How would you be able to tell individual moves like this? Would you
have to separate it out, i.e. create a bit-board with only one square?
In a similar vein, if there were to be multiple moves, how would one
be able to distinguish between them?
There are some different ways you could handle generating moves from bitboards.
In my engine, what I do is go through the bitboard of pawns for the side to move, and generate the moves each individual pawn has. Here's most of the relevant code:
func genPawnMoves(pos *Position, moves *MoveList) {
usBB := pos.Sides[pos.SideToMove]
enemyBB := pos.Sides[pos.SideToMove^1]
pawnsBB := pos.Pieces[Pawn] & pos.Sides[pos.SideToMove]
// For each pawn on our side...
for pawnsBB != 0 {
from := pawnsBB.PopBit()
pawnOnePush := PawnPushes[pos.SideToMove][from] & ^(usBB | enemyBB)
pawnTwoPush := ((pawnOnePush & MaskRank[Rank6]) << 8) & ^(usBB | enemyBB)
if pos.SideToMove == White {
pawnTwoPush = ((pawnOnePush & MaskRank[Rank3]) >> 8) & ^(usBB | enemyBB)
}
// calculate the push move for the pawn...
pawnPush := pawnOnePush | pawnTwoPush
// and the attacks.
pawnAttacks := PawnAttacks[pos.SideToMove][from]
// Generate pawn push moves
for pawnPush != 0 {
to := pawnPush.PopBit()
if isPromoting(pos.SideToMove, to) {
makePromotionMoves(pos, from, to, moves)
continue
}
moves.AddMove(NewMove(from, to, Quiet, NoFlag))
}
// Generate pawn attack moves.
for pawnAttacks != 0 {
to := pawnAttacks.PopBit()
toBB := SquareBB[to]
// Check for en passant moves.
if to == pos.EPSq {
moves.AddMove(NewMove(from, to, Attack, AttackEP))
} else if toBB&enemyBB != 0 {
if isPromoting(pos.SideToMove, to) {
makePromotionMoves(pos, from, to, moves)
continue
}
moves.AddMove(NewMove(from, to, Attack, NoFlag))
}
}
}
}
Notice how I loop through each bit of the pawn bitboard, and then generate all of the possible moves that pawn might have, verify those moves, and then loop through each bit of those move bitboards to generate each individual move.
Note PawnPushes
and PawnAttacks
are lookup tables where I precalculate what move has a pawn depending on it's square and color (not including double pushes, as those are calculated on the fly as you can see).
If you want to see more of the detail in my code, see here: https://github.com/algerbrex/blunder/blob/main/engine/