gambit
A chess engine in Scala 3. Move generation, position evaluation and search - a complete chess brain, built with scala-cli.
A chess engine in Scala 3. Three hard things at once: flawless move generation, meaningful position evaluation and a search that picks a good move in reasonable time. A complete brain to play chess.
Overview
A chess engine only looks like one project. It is three subsystems, each able to ruin the whole thing in its own way, and only together do they produce something that plays sensibly. gambit is about making those three parts agree with each other well enough that the result starts to resemble a real opponent, not a random move generator.
Scala 3 gives an expressive language here for modeling the board, moves and the tree of variations. But the real challenge is not syntactic, it is algorithmic: a flawless generator, a fair evaluation and a search that does not compute forever.
Three problems that must agree
A move generator that lets one illegal move slip through per million positions will make the engine play something impossible. An evaluation that weighs pieces wrong will steer it confidently into a loss. A search without pruning will think for hours about a move that should take a second.
every legal move in any position, including castling, en passant and promotion.
a number expressing who stands better while the game is still on.
alpha-beta that discards branches not worth computing.
None of these three can be dismissed. An engine weak in any one of them will lose, and for a specific, pinpointable reason, not a general weakness.
Alpha-beta, the art of not computing
Naive search examines every possible continuation, and there are billions of them just a few moves deep. Alpha-beta pruning notices that if one of the opponent's replies already refutes a line, the rest of their replies need not be computed. With good move ordering it cuts the space so hard that the engine reaches deeper in the same time.
Nodes to search at the same depth (illustrative, thousands)
This is not a minor optimization but the difference between an engine that sees three moves ahead and one that sees six. In chess that depth translates directly into playing strength.
Perft, the proof of generator correctness
Move generator correctness is verified with so-called perft: you count all positions reachable at a given depth and compare against numbers the whole chess community knows by heart. If your number is off, you have a bug somewhere, and it shows you exactly at which depth the divergence begins.
Perft from the starting position
| Depth | Position count |
|---|---|
| 1 | 20 |
| 2 | 400 |
| 3 | 8902 |
| 4 | 197281 |
| 5 | 4865609 |
The result is a complete engine that takes a position and returns a move: the generator lays out every legal continuation, the evaluation says which leads somewhere better, and alpha-beta searches as deep as time allows. Three subsystems that are only parts on their own together make an opponent that can play.
Perft is the textbook example of a test that can actually fail. It does not check that something works, it compares your number against a number known in advance, so any bug in the generator immediately throws off the result.
More projects
More work from the same category - see how we tackle similar challenges.
Have a similar project?
Get in touch - a quote is free and comes back within an hour.



