When you sit down to play chess online, there's a brain on the server side that checks whether your moves are legal, prevents cheating, and enforces the rules of the game. That brain is the chess engine.
In this post, we'll walk through how a chess engine is implemented under the hood—specifically one written in Go, backed by the blazing speed of bitboards. Whether you're building your own chess app or just curious about how engines work, this post dives into the guts of what makes the game tick.
At its core, the engine is the rulebook of chess in code form. It needs to:
Understand how each piece moves
Enforce all special rules (castling, en passant, promotion)
Reject illegal moves
Detect checks, pins, checkmates, and stalemates
It's not responsible for persistence (that's the repository's job), nor for coordinating services (handled by the service layer). The engine lives in its own pure Go package—no external dependencies, just logic.
Let's say it's the first move of the game, and White tries e2 to e4. Here's what the engine does to validate this move:
Check the source square (
e2):Is there a White Pawn on it?
Check the target square (
e4):Is it empty?
Pawn-specific rules:
Is this the pawn's first move? If so, can it move 2 squares?
King safety:
After making this move hypothetically, does it leave the King in check?
The engine doesn't just guess. It checks all these conditions explicitly and systematically.
We want our engine to be fast—like "respond in milliseconds" fast. That's where bitboards come in.
A bitboard is a 64-bit unsigned integer (uint64). Each bit corresponds to one square on the chess board. A 1 means something is true about that square. For example:
Bitboard of White Pawns: 1s where pawns are
Bitboard of all occupied squares: 1s wherever any piece is present
Imagine the board as this:
8 | 0 0 0 0 0 0 0 0
7 | 0 0 0 0 0 0 0 0
6 | 0 0 0 0 0 0 0 0
5 | 0 0 0 0 0 0 0 0
4 | 0 0 0 0 0 0 0 0
3 | 0 0 0 0 0 0 0 0
2 | 1 1 1 1 1 1 1 1 ← White Pawns
1 | 0 0 0 0 0 0 0 0
a b c d e f g h
This is represented in Go as:
var whitePawns uint64 = 0x000000000000FF00
With bitboards, you can:
Get all pawns with a single value
Find empty squares:
^occupiedSquaresCalculate legal pawn moves with shifts like
whitePawns << 8
Bitwise operations (AND, OR, SHIFT) are insanely fast—no loops required.
Here's how you'd generate single-step pawn moves using bitboards in Go:
singleMoves := (whitePawns << 8) & ^occupiedSquares
Want to allow double moves from the 2nd rank?
doubleMoves := ((whitePawns & rank2Mask) << 16) & ^occupiedSquares
Add attack logic (diagonal captures), en passant rules, and you're already halfway to a serious chess engine.
One of the trickiest parts is ensuring that a move doesn't leave your king in check. Here's the approach:
Make the move virtually (don't modify real board yet)
Recalculate all opponent attack bitboards
If the king is under attack, reject the move
This way, the engine enforces all safety rules without relying on the game state from external services.
By keeping the engine as a pure Go package:
It's portable and testable
There are no dependencies on HTTP, database, or external services
All the logic lives in memory and runs lightning-fast
You can plug this engine into your service layer or even into a CLI-based chess app or bot.
Unit tests are critical. Since the engine doesn't rely on any infrastructure, it's easy to write tests like:
assert.True(t, engine.IsMoveLegal("e2", "e4", whiteBoard))
assert.False(t, engine.IsMoveLegal("e2", "e5", whiteBoard))
You can simulate full games, generate perft (performance test) numbers, and validate against known legal positions.
Now that the engine can validate moves and generate legal positions, you can layer on:
Move scoring and search (for an AI opponent)
Threefold repetition detection
Draws by insufficient material
But even without AI, a robust engine ensures fair, rule-compliant play—which is essential for multiplayer games, tournaments, or bots.
The Engine is the brain that validates chess rules
It uses bitboards (64-bit integers) to represent the board and calculate legal moves ultra-fast
All logic is implemented in a pure Go package—clean, testable, and fast
Bitboards let you write elegant, blazing-fast chess logic without messy loops or nested conditionals
If you're building a chess app or just love systems programming, bitboards are one of the most satisfying tricks in the book.
Repository: https://github.com/namanvashistha/chess
No posts

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.