Project History
1. The Spark (2013)
In the summer of 2013, while I was still in high school, I stumbled upon an article about Ultimate Tic-Tac-Toe. At the time, I didn’t know English, so I read a translation – but the logic transcended language. I loved it instantly:
- It offered a small set of simple rules that provided immense complexity, much like John Conway’s Game of Life.
- It required deep strategic thinking, yet lacked the rigid baggage of Chess pieces.
I began playing it periodically with friends and family, burning through countless reams of paper to draw the nested grids.
2. The Vision: From Paper to Code (2016)
Later, at university, I wanted to play with friends across different cities. Finding no quality online versions, I decided to build one myself.
Since childhood, I have been obsessed with generalization: learning or designing universal theories that describe all the essential details and cover as much practice as possible, be it physics or game logic. Consequently, I found it incredibly satisfying to generalise the game engine to handle arbitrary sets of parameters:
- S (Side Length of a Block): moving beyond the
3×3standard, including smaller, fast-paced2×2(where draws are impossible), and larger4×4or5×5. - N (Layers Nesting Depth): allowing for classic Noughts and Crosses, Super/Meta/Ultimate Tic-Tac-Toe, or even deeper fractal layers.
- Multiple Teams: supporting more than just two players (
XandO); though this was not fun enough at first glance.
For instance, a classic XO game is represented as S3 N1 in my format, while Ultimate Tic-Tac-Toe becomes S3 N2, and there are many other configurations!
I dove into game AI, implementing a Minimax algorithm with alpha-beta pruning and a specialized heuristic evaluation capable of adapting to these various board configurations.
3. The Initial Development
Originally, I explored C++/Qt for cross-platform support. However, once I saw the result on a smartphone, I wasn’t satisfied, the UI felt clunky – it didn’t use native elements. I refused to ship an “ugly” product. I could have integrated native code to access OS interface elements, but that felt like patching together a Frankenstein’s monster.
I decided to go fully native: separate implementations using Objective-C for iOS and Java for Android. This allowed for a polished, platform-specific experience despite parallel codebases. For the backend, I built a Python server using the asynchronous Tornado framework (before async/await was standard). I even implemented a double-API fallback: the game attempts a WebSocket connection for speed but falls back to HTTP if a Wi-Fi network blocks WS protocol; of course, all via SSL/TLS transport. This was my first experience with backend development and Linux interaction. I also developed a client-side browser version, though it lacked multiplayer support at the time.
I also dedicated some time to branding – crafting the name and icon. I wanted something simple yet unique, memorable and clearly linked to the “X and O” heritage. In the end, I arrived at a design that I feel truly resonates with the game’s identity.
4. The Reality of the Market
To make the game global, I worked with friends to translate it into eight languages. But being a student developer is expensive. Between the $100/year Apple Developer fee and server costs, I added ads to help the game pay for itself. I even invested an additional $100 into advertising to gain traction – the primary reason the game reached thousands of installs on Android and hundreds on iOS.
However, the financial reality was a cold shower: I earned only $12 in one year – not even enough to reach the withdrawal threshold! The ROI (Return on Investment) was effectively -90%… Paradoxically (though perhaps not surprisingly), while Android had more users, it only generated ~$1.50, with the remainder coming from the Apple platform. At least, I met many interesting people from all over the world through the in-game chat!
Between the lack of marketing knowledge (I hadn’t heard of Reddit or Discord yet) and the constant maintenance required by Google and Apple’s changing policies, the original mobile versions eventually fell off the App Store and Play Market.
5. The Web Rebirth (2022)
In the spring of 2022, I decided to make a single full-featured browser game version using modern technologies, so I made:
- a new server with async-native FastAPI keeping pretty much the same API.
- and new web TacticToy version with React.js which is much easier to develop thanks to modularity (vanilla JS version was a single file with 2k of lines!), but with multiplayer support over WS/HTTP, like older mobile game versions. It’s still playable: v2.TacticToy.com
This was made mostly by personal motivation: to keep my “child” alive and to better learn React.js, so I spent almost zero efforts into marketing, just published on a couple gamedev websites, though with seemingly no recognition.
6. The Universal TT Engine in Rust
Having experience with various programming languages and technologies (even more than mentioned here) and a passion to develop diverse projects, I grew frustrated by the need to maintain different knowledge bases to work on them. Therefore, for years I searched for the “one to rule them all” – a technology capable of high performance and true cross-platform reach. I was looking at and sometimes experimented with Dart/Flutter, React Native, GoLang, etc, but I disliked them. In contrast, the more I learned Rust, the more I liked it. Decided to start actively learning it and using for some projects in July 2023.
In parallel to my jobs, other projects and life events, I thought about TacticToy, periodically playing it with some friends and I imagined how can I improve, expand, advance it even more?
- Besides adding animations and SFX, I planned to decouple the block side length and win-line length (a concept I later learned is known as the m,n,k-game or k-in-a-row). It’s now the L parameter.
- This also helps to fit multiple teams way better!
- S parameter is no longer capped at 5, it can be up to 16. Instead, there are restrictions on total board side length (calculated by
S^N < 100) and volume (S ^ (N*D) < 1000). - I thought that my algorithm is easy to generalise for 3D and even 4-dimensional grids, and this is too fun not to do! And this is the D parameter of course.
- Although Minimax algorithm is reliable and pretty efficient with alpha-beta pruning, it struggles with the state-space explosion on larger boards causing the bot to hang or lag on larger boards, which is unacceptable considering the changes above, so I was thinking about shifting to Monte Carlo Tree Search (MCTS) algorithm to better control bots “thinking” time independently of larger board complexities.
- Why it fits better here? Well, Minimax is a deterministic algorithm, it tries to see the end of the world (at least to some extent), while MCTS is a probabilistic algorithm: it explores the most promising future scenarios, without brute-force exhaustive search, making it the only viable choice for managing state-space explosion.
- I knew that ultimate XO game versions differ in how they treat already won blocks: some allow to send and move in, some forbid. I’d like my game to let players play the style they prefer.
- Win Condition setting: adding support for “Area Control” (winning a majority of pre-highest sub-boards) rather than just a linear three-blocks-in-a-row.
- Time control: I suppose it’s an important mechanic for multiplayer mode that makes the game feel like a true competition! And the game should allow to choose preferred time limit, be it 10 seconds or 10 hours, as well as the desired punishment effect for a passed deadline: a random move or an instant disqualification.
- The original TT version’s multiplayer mode allowed to have multiple players in the same team, but they had to move in round-robin order, and it may be hard for several people to coordinate, so I’d like to allow any team member to make a move on team’s turn.
- Better i18n (internationalization): I decided to add more than 20 of the most widely spoken languages and even several artificial ones! This was hard, but modern AIs make a good help.
7. Say No to Cheating: Kyū Rule
I also reflected about abusing game mechanics – dictating your opponent’s moves from the start, holding them in a single block, totally controlling the game flow and forcing a win:
- I designed a rule that forbids sending your opponent to the same block consequently, naming it the Kyū rule 窮 signifying “exhaustion” or “strangling” rule. It’s a thematic nod to the Ko rule in the Go – game that I also love – that means “eternity” or “repetition” and prevents recursively useless moves.
- The issue could also be managed by random initial moves (following Go style metaphors, I’d name them probes or scouts), or some cells restricted to move in, kind of obstacles, which also keeps the opening game fresh and unpredictable – I decided to introduce both as a part of board parameters.
8. The Modern Development
In August 2024, I began the ultimate rewrite. Using Rust for a shared core between the server and client, I am building the definitive version of TacticToy. My goal is simple: to create the most comprehensive, strategically deep and technically polished implementation of N-dimensional Tic-Tac-Toe ever made.
Starting a new version of TT in Rust, I first re-implemented the old game engine and Minimax bot algorithm. With the need to test and debug, but having no single obviously the best cross-platform rendering framework for Rust, I decided to focus on core engine extending, while testing and debugging in terminal. Previously, I never played nor made console games, but made one for TacticToy, although I doubt I’ll publish it, I still liked the Rust ecosystem with powerful yet simple to use crates to deal with terminal. And I really like the algorithm I made to visualize arbitrary boards, including 3D and even 4D as 2D slices.
After introducing L and D board parameters, implementing MCTS bot algorithm, it’s time to work on drawing and UI. Having a need of both 2D and 3D rendering support, I attempted to use Bevy suspiciously learning the Entity-Component System paradigm (ECS) – while it seems great for games full of different objects and mechanics, it seems too much for a game with a single fixed-size state structure, though might be helpful for decoupling UI and physical state, enabling animations.
Besides of technical issues, designing the UI in an actual 3D strategy game is really hard. I decided to focus on other features staying in 2D, re-implementing and updating old web UI via WASM and backend server, all in Rust. I explored Leptos, Yew and Dioxus – and chose the last one for its cross-platform support beyond the web and a bunch of other nice features.
Currently, this version is still in testing stage, but already pretty playable: 2D.TacticToy.com.