Nine to One
A real-time multiplayer card game for two to five players, built for the phone. Empty seats fill up with bots, including one trained by self-play.
- Game
- Completed
- 2026
- 1 semaines
- Next.js
- TypeScript
- FastAPI
- WebSocket
- PyTorch
- NumPy
- PostgreSQL
- Tailwind CSS

A card game I play with my friends that nobody had brought online. You enter a nickname, create a table and share its code: no account, no install, the address opens in a phone browser and the game starts.
Real time
Every table lives in the server's memory and talks to players over WebSocket. The server is the only referee: it applies the rules, computes the legal moves and sends each player strictly what they are allowed to see. The client holds no game logic, it renders a state and forwards intentions.
The rules engine is covered by 68 tests. A card game is mostly a long list of edge cases, and each one earned its test after catching me out mid-game.
The bots
Three levels. The first plays a random legal move, the second follows a hand-written heuristic, the third is a neural network trained by self-play with reinforcement learning, then exported to NumPy so production runs without PyTorch. When its turn comes, it refines the decision with a search over the cards it cannot see.
That bot does not cheat: it gets exactly the view of a player sitting in its seat. It thinks in a separate thread, with a bounded time budget and a cap on concurrent searches, so the network loop keeps serving the other tables meanwhile. The whole process fits in 75 MB, network weights included, on a VPS shared with my other sites.