Infinitus: The Rules Engine Has No Scene
- Published
- Read
- 3 min
- By
- creationwasteland
RelatedFallen Sand: A World Where Every Pixel Is SimulatedInfinitus: Wrapping WebGL in a React ComponentUnity Development: Queues Are Not All Bad! (Part 3)
Infinitus is a chess-like strategy game I am building in Unity. The pieces are persistent: they have names, they gain experience and levels, and they carry a history from match to match. The moves are not hard-coded; each piece's actions are data. There is an AI, there are replays, and there is online play. Nearly all of that rests on one decision I made early and have defended ever since: the rules engine has no scene.
The law
The project keeps a short list of rules I treat as laws, meaning a violation is a bug rather than a style problem. The first one is that Infinitus.Core, the assembly that knows how the game works, contains nothing from the presentation side. No MonoBehaviours, no scene references, no UnityEngine.Object anywhere near the move generator. Move generation is pure C# over a MatchState. Reading something as harmless as a GameObject's .name throws when you do it off the main thread, so even that is banned there.
This is not purity for its own sake. It is what the game needed, and here is why.
The AI needs a board it can scribble on
The opponent is a minimax search. It tries a move, evaluates the position, tries the next move, and does that thousands of times a turn. Copying the board for every node would be slow, so the search mutates the live match state and unwinds. That only works if every action's effect undoes exactly, bit for bit, and a hasher proves it in tests: apply, undo, compare. And because the search runs on a worker thread so the UI stays responsive, the state it searches cannot touch Unity at all.
// The shape of it. Every effect knows how to take itself back.
var hashBefore = BoardHasher.Hash(state);
action.Apply(state);
var score = Evaluate(state);
action.Undo(state);
Assert.AreEqual(hashBefore, BoardHasher.Hash(state));
Replays and online play need determinism
If a match is a sequence of actions over a seeded state, then a replay is that sequence played again, and two machines playing online can each run the same rules and compare per-turn hashes to catch a desync. For that to hold, nothing in the rules may call UnityEngine.Random. Anything that needs randomness goes through a MatchRandom that is a pure function of the seed. The visual layer can be as random as it likes. It just cannot decide anything.
Screens render; they do not decide
That sentence is another of the laws. Every question a screen asks, such as which moves are legal, what a piece costs, or whether a player can afford a pack, is answered by a plain C# class that a headless test can ask too. The screens stay thin. This is the part that pays off every day, because the test suite covers the whole game without opening the editor. There are over 1,200 edit-mode tests at the time of writing, and they run in a couple of minutes.
Tests that fail when the documentation lies
One more habit grew out of this. The design documents are checked by tests. Every piece has a markdown page with its numbers, and a test fails if a shipped piece has no page, or if a campaign fight is priced differently from what its design document says. It sounds fussy. In practice it means the documentation is never wrong, which matters when you come back to a system after two months and have to trust what you wrote.
What it costs
You pay for all of this in plumbing. Every new piece needs an asset, a definition, a codex entry, a price and a test. New content takes longer to add than it would in a scene-first project, and the first few weeks felt slow because of it. I think the trade is right for this game. The things that would have been impossible otherwise, the AI, the replays, and online verdicts settled on a server, are exactly the things that make it more than a chess board with new sprites.
Infinitus is in development for PC and Android. There is a page for it under Products.

Like what I said? Hate what I said? Tell me what you think: kameron@creation-wasteland.com