Chess engine, pt. 0: Index
Building chess engines, that is, making computers play chess, is seemingly a common pastime of programmers. Of course, I had to try it too, so I created my own engine, chess-inator, from scratch. As it turns out, chess engine development is incredibly addicting (I say this from experience), because there is always more room for improvement in your engine. Now though, chess-inator can beat most chess players I know personally, so I’m stopping before I spend way too many hours on this project.
This blog post series is essentially a log of chess-inator’s development, including important tips and information that I had difficulty finding from other online sources. Even though the series is mostly about my own engine, I wrote these posts as if they were a tutorial, because I like that tone. These posts are intended to focus on practical rather than theoretical aspects; you should technically be able to write an engine by following along.
The target audience of this blog series is me from 2024, that is a version of myself that doesn’t know anything about chess engine development. Ideally, this series contains all the essentials to get started with writing an engine without any prior experience. I assume you, the reader, are proficient with some programming language,1 you’ve played chess before, and you know the rules of the game (google en passant). In this series, I use pseudo-Python for code examples, but my real chess engine project uses Rust for engine code.
Before I begin, here are the mandatory acknowledgements. Thanks to
- the Chess Programming Wiki
- the members of the Engine Programming Discord
- and all the other people who publish resources about chess engine development online
for providing valuable information about chess programming and making this domain accessible to everyone. This project would really not be possible without them.
Index
Here is an overview of all the posts in this series:
- Part 1: Getting started: In this post, I cover enough for you to write a chess engine that plays random moves. This is the base that the next parts will build upon. If you follow along with this post, you will quickly be able to play games against the engine you create.
- Part 2: Negamax search: I cover the negamax search algorithm, which is a variation of minmax. Once negamax is implemented, the chess engine will play moves more intelligently (i.e. not random moves).
- Part 3: Elo, and rigorous SPRT testing: I introduce the Sequential Probability Ratio Test, which is a statistical tool that can be used to rigorously test a chess engine’s performance. SPRT is very important in modern chess engine development.
- Part 4: α-β pruning and better search: I go over some of the main optimizations to negamax: alpha-beta pruning, the transposition table, move ordering, and iterative deepening.
- Part 5: Quiescence search, endgames, repetition avoidance: In this part, I explain how to fix some really annoying bugs in the chess engine. These bugs are inherent to how we implement negamax. After this part, the engine plays chess at a beginner level, albeit with a quite unnatural (i.e. bad) playstyle.
- Part 6: Neural-net evaluation: I explain how neural networks, specifically the NNUE, can be used to improve a chess engine’s performance. This post goes over chess-inator’s NNUE architecture in great detail.
Some of my favourite posts in this series are part 3 (SPRT) and part 6 (NNUE). SPRT is something you should use as soon as possible when developing a chess engine, yet I’ve never heard of it before starting this project. If I had to recommend one part of this blog series, it would be the part about SPRT. It’s not an exciting subject, but it is essential to making a good chess engine.
I also had fun writing the NNUE post, because I think there is a shortage of resources for beginners. In my research, I found lots of general summaries that explain NNUE’s general concept, and also deep dives about Stockfish’s complex NNUE architecture. However, resources for my skill level are rarer. The aim in my NNUE post is to explain how a simple (and easy to understand) NNUE architecture works, with enough detail for you to follow along with its implementation.
In total, this blog series was written over a period of a few months,
which is unsurprising given that it is really long2 compared to my other writings.
I hope that some of you find will it useful.
If you find any mistakes in the posts (such as mixing up an i
and a j
, or a typo),
please tell me.
Feel free to write to me if you have any other comments.
Now, let’s begin: Part 1 →
Note: The dates given for all the blog posts are not the publication date; they’re the date that I created each document. Part 0 (this page) was written on 2025-07-07, but it has been backdated so that the order of the posts on the home page makes sense.
-
Ideally, the programming language you use for a chess engine is a performant language like C++, Rust, Java, C#. If your language is generally faster, then your engine will be better because it can do more calculations in the same amount of time. ↩
-
This series is roughly 25k words, which is five times more than the LC-3 article, the previous record holder. ↩