user32600: If I have a pawn bitboard like this, for example,
00000000
00000000
00000000
00000000
00001000
00000001
11110110
00000000

generating all of the, say, legal capture moves to the right will perform a north-east shift on the bitboard, like so.
00000000
00000000
00000000
00000100
00000000
01111011
00000000
00000000

Normally, moves are stored as square that the piece moved from, and square that the piece moved to, with special move considerations. But this approach, at least to me, appears to only create a map of positions that these pieces are attacking or can move to.
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?

user27860: 
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/

32600: <p>If I have a pawn bitboard like this, for example,</p>
<pre><code>00000000
00000000
00000000
00000000
00001000
00000001
11110110
00000000
</code></pre>
<p>generating all of the, say, legal capture moves to the right will perform a north-east shift on the bitboard, like so.</p>
<pre><code>00000000
00000000
00000000
00000100
00000000
01111011
00000000
00000000
</code></pre>
<p>Normally, moves are stored as square that the piece moved from, and square that the piece moved to, with special move considerations. But this approach, at least to me, appears to only create a map of positions that these pieces are attacking or can move to.</p>
<p>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?</p>
 27860: <blockquote>
<p>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?</p>
</blockquote>
<p>There are some different ways you could handle generating moves from bitboards.</p>
<p>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:</p>
<pre><code>func genPawnMoves(pos *Position, moves *MoveList) {
    usBB := pos.Sides[pos.SideToMove]
    enemyBB := pos.Sides[pos.SideToMove^1]
    pawnsBB := pos.Pieces[Pawn] &amp; pos.Sides[pos.SideToMove]

    // For each pawn on our side...
    for pawnsBB != 0 {
        from := pawnsBB.PopBit()

        pawnOnePush := PawnPushes[pos.SideToMove][from] &amp; ^(usBB | enemyBB)
        pawnTwoPush := ((pawnOnePush &amp; MaskRank[Rank6]) &lt;&lt; 8) &amp; ^(usBB | enemyBB)
        if pos.SideToMove == White {
            pawnTwoPush = ((pawnOnePush &amp; MaskRank[Rank3]) &gt;&gt; 8) &amp; ^(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&amp;enemyBB != 0 {
                if isPromoting(pos.SideToMove, to) {
                    makePromotionMoves(pos, from, to, moves)
                    continue
                }
                moves.AddMove(NewMove(from, to, Attack, NoFlag))
            }
        }
    }
}
</code></pre>
<p>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.</p>
<p>Note <a href="https://github.com/algerbrex/blunder/blob/main/engine/tables.go#L109" rel="nofollow noreferrer"><code>PawnPushes</code> and <code>PawnAttacks</code> are lookup tables</a> 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).</p>
<p>If you want to see more of the detail in my code, see here: <a href="https://github.com/algerbrex/blunder/blob/main/engine/" rel="nofollow noreferrer">https://github.com/algerbrex/blunder/blob/main/engine/</a></p>
