Skip to content

Let's build a move generator

A seven-part series on building a correct, cross-platform chess move generator in C# — from FEN parsing through magic bitboards to fully legal move generation.

Part 1

The Pipeline and Perft

A chess engine plays moves by searching: it explores the tree of "what if we played this, then they played that, then..." and picks the move at the root that leads to the best position. Search is glamorous. But search is also useless without a fast and correct **move generator** underneath — the function that, given a position, hands back every legal move available.

Read part 1

Part 2

Representing the Board

A position is more than pieces on squares. To play chess we need to track who's to move, whether either side can still castle, where en-passant captures are available, and a couple of counters for the draw rules. We need a representation that holds all of that and lets us answer two questions fast:

Read part 2

Part 3

Encoding a Move

We've got a `Position` we can load from FEN and print back. Next we need a representation for the moves we'll generate from it. A move needs to carry enough information that, given a `Position`, we can both apply it and undo it without ambiguity.

Read part 3

Part 4

Generating Pseudo-Legal Moves

This is the heart of the series. Given a `Position`, we want a function that returns every **pseudo-legal** move: every move that follows the rules of piece movement (pawns push, knights hop, sliders slide) without yet checking whether the result leaves the king in check. Legality comes in Part 7; today we just enumerate.

Read part 4

Part 5

Making a Move

We've got a generator that produces every pseudo-legal move. To use it — for perft, for search, for anything — we need to **apply** each move and then **reverse** it so the next sibling move starts from the same position.

Read part 5

Part 6

Magic Bitboards

The generator from Part 4 is correct, and the make/unmake from Part 5 is correct, and together they give us matching perft numbers. They're also slow. Most of the time is spent in `RookAttacks` and `BishopAttacks` — the classical ray-scan does up to four bitscans and four conditional XORs per slider, every time it's called, on every search node.

Read part 6

Part 7

Legal Move Generation

Our generator from Part 4 emits pseudo-legal moves, and the perft loop in Part 5 filters out the ones that leave our king in check by making each one, asking "is our king attacked?", and rolling it back. That gets us correct perft numbers, but it does a lot of pointless work — every search node tries moves that we could have known were illegal up front.

Read part 7