Introduction
Hi. I plan to use this blog to document my personal project to build a platform for playtesting board games against AI opponents, starting with the game Kingdomino.
A primary motivation for this project is to learn a bunch of new-to-me tools like TypeScript and TensorFlow, so don’t expect expert-level knowledge!
I’ll start in this post by documenting the tools I chose:
AlphaZero
I’m using the AlphaZero learning method because it’s proven to achieve superhuman ability on board games and because I can understand it well enough to implement it. AlphaZero is a combination of neural network heuristics and tree search. Its predecessor, AlphaGo, partly learns from human games, which aren’t available for most board games, and its successor, MuZero, focuses on cases where the rules of the environment are unknown, which isn’t true for board games.
Some modifications were needed to support games with more than two players and random events.
TypeScript
One of the goals of the project is local gameplay in the browser for low latency UX and offline availability. That goal creates a strong incentive to implement game logic in JavaScript. There are lots of languages that compile to JavaScript, and there’s WASM, but TypeScript is the most mature way to target the browser with a reasonable language.
Game logic also needs to run during neural network training, which is unlikely to happen in a browser, but running JavaScript outside of a browser isn’t hard…
Node.js
I needed a platform in which to run both the JavaScript game logic and neural network training and inference. Node.js has that thanks to TensorFlow.js which has specific support for Node.js.
There are other JS runtimes but they aren’t as mature as Node.js and I don’t know whether they support TensorFlow.js.
TensorFlow.js
TensorFlow.js is to my knowledge the only neural network library that supports training and inference in JavaScript. It supports CUDA in Node.js and WebGL in browsers. Another option would be to IPC to a service that runs training and inference using some other platform like PyTorch but that would add complexity and reduce performance.
Turborepo
Turborepo is a tool for managing JavaScript monorepos. Even though I won’t have that much code I wanted to start out with a monorepo. Monorepos enforce modularity so the code can be published as multiple packages in the future if desired without giving up the ability to do atomic commits across packages.
Immutable.js
Persistent data structures are useful in AlphaZero because every game state in a self-play episode needs to be retained for training. Mutable data structures would be dangerous for handling game state since nothing would prevent one from inadvertently mutating a previous state. Immutable.js provides persistent Sets, Maps, and Sequences which are used to manage game state.
It also provides the ValueObject
interface which allows non-primitive objects to used as keys in collections. My code uses Immutable.js data structures in some cases just for that capability. I don’t know how JS programmers survive otherwise given the lack of that capability in the native collection types.
Io-ts
I use Io-ts to define the file formats for self-play episode data.
Next.js
This project needs client-side JavaScript for browser gameplay. I have no experience in web frontend but Next.js and React seem to have the largest community among the frontend frameworks. React has been easy to use so far though its ergonomics and efficiency are worse than Jetpack Compose which is the reactive framework I am familiar with.
Vitest
I couldn’t easily get Jest working with TypeScript tests, while Vitest worked out of the box, so Vitest it is.
Pnpm
I’m using pnpm for package management since I’m using fine-grained packages in a monorepo and pnpm deduplicates shared dependencies across packages in a workspace.
That’s all for now; to be continued!