Portrait of David Findley

Nested Tic-Tac-Toe

Project URL: https://tictactoe.findley.dev
Source Code: https://gitlab.com/findley/tic-tac-tic-tac-toe
Technologies: JavaScript, HTML, CSS, WebSockets, Kubernetes

I first saw Ultimate Tic-Tac-Toe in college and was immediately fascinated by it. As you probably know, ordinary tic-tac-toe can be played perfectly by following a few simple rules. Fortunately this is not the case with nested or "ultimate" tic-tac-toe. I'm no expert on statistics and game-theory, so I won't pretend that I can explain the competitive nature of the game. I see the game as a novelty that's a good yet simple upgrade from the original.

I've never been very good at strategy board games, but my experience with playing chess is that I have a feel for the "state" of the game (if I'm losing just a lit bit, or if I'm losing a lot). With nested tic-tac-toe, that seems much more elusive. It's very difficult for a casual player to understand if they're doing well or not. I always feel like I'm losing even when I win. Another way to put it: The moves in the early game feel extremely random until suddenly the game collapses and somebody wins.

I built my own web app to play the game with friends. It allows for online play with another person or local play. I didn't attempt to make an AI opponent, but you can find a few other implementations that do.



My primary goal with this project was to keep things as simple as possible. I see it as a little rebellion against the ever growing complexity of building web applications. The amount of tooling and dependencies required for something like create-react-app is nauseating, and I don't think it should be the first thing we reach to for every project. Modern browsers provide an immense amount of functionality, and a small project can go a long way without the need for all of these complexities.

The front-end has zero css/javascript dependences. There's no build process, just an html file, a couple of mjs (ES6 modules) files, and a css file. You can just open the html file directly in the browser.

The back-end is written in nodejs so that it can share some of the game logic with the front-end. It has just two direct dependencies: "ws" and "node-static". I have no intentions of implementing websockets from scratch in node, so ws handles that. I could have dropped node-static, which is just there to host the static front-end, but I was being lazy. It would have been better to let nginx host the static assets and proxy the node websocket server.

Of course, not having to deal with persistent data storage can make any app significantly less complex. So not having a database combined with dropping all the standard javascript tooling made this project refreshingly simple.