Skip to content

Repository files navigation

AlphaBia

A Makruk (Thai chess) engine trained from zero by AlphaZero-style self-play, on a single RTX 4060 at home.

This is a hobby project. I wanted to see how far a normal gaming PC can push a variant that has almost no neural engines.

Credits

The whole codebase is built on KataGomo by hzyhhzy, specifically the AnimalChess2025 branch, which itself is a fork of KataGo by lightvector. I did not write the engine core, the search, or the training pipeline - those people did, and they did it well. What I added is the Makruk game logic, rules, tests, and the training runs.

Btw Claude helped me a lot throughout this project :)

What's implemented

  • Full Makruk rules: piece movement (Khun, Rua, Ma, Khon, Met, Bia), directional pieces, Bia promotion to Bia Gae, check, checkmate, and stalemate

  • Thai draw counting rules:

    • 2 rooks: 8
    • 1 rook: 16
    • 2 bishops: 22
    • 2 knights: 32
    • 1 bishop: 44
    • 1 knight: 64
    • Only Met / promoted Bia Gae remaining: 64
  • 64-move board counting rule

  • Threefold repetition draw

  • One move = two engine plies: first selecting the from-square, then selecting the to-square. Keep this in mind if you script against GTP.

  • Test harness that plays real matches against Fairy-Stockfish over UCI, with strict rule enforcement and PGN output: test/engine_match.py

The model

There is one model in the releases: model_192 b15c192. It was trained on my RTX 4060 from random weights, no opening book and no human games. Endgame conversion under the counting rule is the hard part and it is still improving.

Performance

Latest results, az192-s600468224, 25 games per line, alternating colours, strict rule scoring (checkmate needs in-check + zero legal moves, count expiry is a draw, threefold and no-progress are draws):

Opponent Score Elo W-D-L
Fairy-Stockfish skill 8 10-0 - swept
Fairy-Stockfish skill 16 72% (50 games) +164 dominant
Fairy-Stockfish skill 18 58% +56 9-11-5
Fairy-Stockfish skill 20 34% -115 4-9-12

So it is roughly skill 18-19. It beats most human club players, and it takes games off skill 20 - something it never managed for the first month of training.

Two honest caveats:

  • A 10-game match swings about +/-20 percentage points. The same model measured 50%, 30% and 40% on three separate 10-game runs. Everything above is 25+ games; do not trust anything smaller.
  • Skill levels below 20 make Fairy-Stockfish deliberately pick worse moves, so extra thinking time does not help it much. Skill 20 is the only unhandicapped comparison, and that is where the engine still loses.

Progression

Every match is logged to test/eval_history.csv. Pooled by model, 20+ game samples only:

Model (samples) vs skill 16 vs skill 18 vs skill 20
s525711616 40% (30)
s532084224 32% (20)
s540965632 48% (25)
s544851712 45% (20)
s552133120 47% (35)
s560230400 44% (25)
s566654720 50% (35)
s580133888 72% (50) 44% (25) 30% (25)
s586081536 59% (28)
s600468224 34% (25)

It sat at 40-50% against skill 16 for a long stretch - roughly 55M training samples - and then moved to 72%. That jump was not extra training; it was a bug fix. The Python training loader had been applying a 90 degree rotation to half of every batch instead of a horizontal mirror. In Makruk that is illegal, since Bia move forward and promotion has a direction, so half the training signal was teaching a game that does not exist. Everything after s566654720 is trained on correct data.

If your own run plateaus, check that your augmentation is actually legal for your game before you blame the network size.

Continuing training

If you want to keep going, my honest recommendation: don't keep growing this net - start a b20c256 and train it on data generated with model_192 (or its own self-play). The bigger net has a much higher ceiling. Expect around 2-3 days on similar hardware before it reaches the level of the model I'm giving you, and it climbs past it from there.

Things worth knowing before you spend GPU hours:

  • Self-play win/draw statistics and validation loss predicted nothing about real strength here. Loss moved up and down for reasons that had nothing to do with playing well (curriculum changes, validation-set rotation). Only matches against an outside opponent told the truth.
  • Head-to-head matches between your own checkpoints are a decent guard against regressions, but a poor way to pick the best model. One checkpoint won its promotion match at 65% and then scored 15% against Fairy-Stockfish.
  • Most games are drawn. Reaching a winning position is not the problem; converting it is.

Building

Same as KataGo/KataGomo. Linux or WSL:

cd cpp
cmake -B build -DUSE_BACKEND=CUDA -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

Use -DUSE_BACKEND=EIGEN for CPU-only. You need cuDNN for the CUDA backend.

Running

Play/analyze over GTP:

./cpp/build/katago gtp -config <your gtp config> -model model.bin.gz

Self-play training loop (selfplay -> shuffle -> train -> export) is in scripts_makruk/ubuntu_alphazero_train.sh with the config in scripts_makruk/makruk_selfplay_alphazero.cfg. The python training side is under scripts/alphabia/trainsgd/.

Rule unit tests build standalone without any GPU:

bash scripts_makruk/build_selftest.sh
./build_selftest/makruk_selftest.exe

To benchmark against Fairy-Stockfish, drop a fairy-stockfish-largeboard binary into test/ and run test/engine_match.py.

License

This repository is released under the MIT License. See LICENSE.


Releases

Packages

Contributors

Languages