The problem
Sliding Attacks Need Occupancy
Walk each direction until edge or blocker. Simple to code, but loops on every attack query — costly when move gen and eval call attacks millions of times per second.
Precompute all attack patterns for relevant occupancies. At runtime: mask → multiply by magic → shift → index → load attacks. Constant time per slider.
attacks = table[sq][index]
Each square has its own mask, magic number, shift, and slice of the attack table. Built once at engine startup.
Deep dive
Building Blocks
For each square, a bitboard of squares that can block rays excluding the edges. Only these bits affect the attack pattern — rooks see 10–12 relevant bits per square, bishops only 5–9.
A carefully chosen 64-bit constant. When multiplied by the masked occupancy, the high bits (after shift) become a perfect hash — every distinct occupancy maps to a unique table index with no collisions.
For each square, an array of attack bitboards — one entry per occupancy configuration. Filled by brute-force ray scanning during initialization (slow is fine here; runtime must be fast).
Separate masks, magics, shifts, and tables for bishops (diagonals) and rooks (rank + file). A queen on d4 combines both lookups — still O(1).
Intel PEXT extracts masked bits into a dense index without multiply-shift magic. Used in Stockfish and many modern engines on supported hardware — same idea, different instruction.
Visual
Rook on d4 — Occupancy → Attacks
Cyan = blockers on d-file / 4th rank · Purple ♖ = rook
Orange = squares the rook can move to or capture on
Reference
Leapers vs Sliders vs Queen
| Piece | Attack method | Depends on occupancy? | Typical approach |
|---|---|---|---|
| Pawn | Direction tables + captures | Yes (blockers, EP) | pawnAttacks[sq][color] |
| Knight | Fixed 8 targets | No | knightAttacks[sq] |
| King | Fixed 8 targets | No | kingAttacks[sq] |
| Bishop | Diagonal rays | Yes | Magic / PEXT table |
| Rook | Rank + file rays | Yes | Magic / PEXT table |
| Queen | Bishop ∪ rook | Yes | bishopAttacks | rookAttacks |
No magic? Fallbacks exist
Beginner engines often use fancy bitboards (carry-less multiply ray tricks) or plain occupancy scanning. Magic/PEXT is the standard for performance — but correctness matters more than method. Validate with perft after wiring attacks into move gen.
- Build masks from square geometry (exclude board edge)
- Precompute attack table entries at startup via ray scan
- Store magic + shift per square; verify zero hash collisions
- Use same occupancy bitboard for both colors' sliders
Continue the engine series
Magic bitboards feed move generation — explore the full stack on FujiBit.
Related: Move Generation · Engine Anatomy · All Blogs