This post walks through two complementary Petri-net formulations of tic-tac-toe, progressing from a minimal turn-based grid to a memory-augmented model capable of reasoning about win conditions. These examples demonstrate how Petri nets naturally encode available actions, enforce alternation, and accumulate structured history for higher-level reasoning.
The final sections outline how these models can be converted into ODE systems via Petri.jl and how to apply parameter sweeps to explore strategy, reachability, and path likelihoods.
In the first stage, we represent the tic-tac-toe grid as nine places P00–P22, each initialized with a token indicating an empty cell.
For every square we define:
Xij transitions — claim the square for XOij transitions — claim the square for OA dedicated Next place enforces turn-taking:
NextNext is marked, preserving alternationThis structure cleanly separates:
All purely through token movement and local composability—no global logic required.
The second version keeps the same grid & turn logic but introduces a memory layer.
Whenever a move fires (e.g. X00):
P00_X00Similarly, all O moves populate _Oij history places.
This upgrades the model from state of the board to sequence of moves. Now we can reason about why the board reached its state—not just its current configuration.
Once we have history places, we can build pattern collectors—transitions that listen for combinations like:
X00_X01_X02X00_X10_X20X00_X11_X22A pattern collector consumes history tokens from the three required squares, producing a structural token such as:
X_has_top_rowO_has_diagFinally, we add win detection transitions:
win_x fires when any X pattern place markswin_o fires for O patternsThis creates a fully compositional win-detection system without any global conditional logic.
Notice above how a winning set of moves activates a win detection transition that populates the win_x place.
This expanded tic-tac-toe model demonstrates how a simple, familiar game becomes deeply expressive when framed through Petri-net structure. By building the system in layers—first the grid and turn alternation, then history tracking, then pattern collectors and win detection—we move from a minimal rules engine to a fully compositional model capable not only of representing what happened, but why.
Every rule arises locally from token flow. There’s no central controller, no global conditional logic—just the emergent behavior of places, transitions, and structured history. This is exactly the kind of model that scales: easy to embed, extend, analyze, or parameterize.
In a follow-up post, we’ll take this exact Petri net into Petri.jl, where we’ll:
This model forms a solid analytical foundation—next time, we’ll turn it into a dynamical system and explore what the engine beneath the game can tell us.