A chess board at the starting position with move and perspective controls

Personal

Chess Engine

A playable board with an opponent behind it: move generation, alpha-beta search, and an evaluation function that is honest about how little it knows. It beats me, which was the acceptance criterion and remains mildly annoying.

Play the engine kiara-vong.github.io/site/projects/chess · source
RoleEverything
StackJavaScript, canvas
Year2023
NoteIf you want to know more, let me know!
Context

Move generation is the boring, load-bearing part

Everyone starts a chess engine wanting to write the clever search. The search is a week; move generation is a month, because the rules have more exceptions than anyone remembers. En passant, castling through check, pinned pieces, promotion, the fifty-move rule.

None of it is interesting and all of it has to be exactly right, because a search built on top of a subtly wrong move generator produces confident nonsense.

The opening position, with a control bar above it: an autoplay toggle per colour, a speed selector, and a point-of-view switch
actions per second

The search is the same at every setting. This only decides how long it is given, which is the honest way to expose a depth limit.

The whole interface is one bar. Hand either colour to the engine, set how fast it is allowed to think, and choose which way the board faces, which is most of what you want from an engine you are testing rather than playing.
How it works

Searching without wasting the search

Alpha-beta is minimax that stops looking down a line as soon as it proves it cannot beat one already found. How much it saves depends entirely on move ordering: search the best move first and most of the tree never gets visited at all.

So the ordering heuristics matter more than the depth. Captures first, then checks, then everything else, and the improvement is dramatic enough that it changes what depth is affordable.

Both sides handed to the engine, and the speed turned up as the game runs. It is played at 1.8× here, which keeps the acceleration a reader can see and does not invent one. No opening book and no endgame tables, so what you are watching is the search on its own.
01Order first, search secondAlpha-beta only pays off if the good moves come first. The ordering is the optimisation.
02Quiesce at the leavesStopping mid-capture makes the engine hallucinate material. Search captures until the position is quiet.
03Evaluate honestlyMaterial, position, mobility. It has no opening book and no endgame tables, and it should not pretend otherwise.
What it taught me

Correctness before cleverness

I wrote the search first and spent a fortnight debugging an engine that was fine. The bug was in castling. Building the unglamorous layer properly and testing it against known positions would have cost two days and saved twelve.