Skip to content
FR
Back

tournament-engine

A tournament engine where a format declares a graph, and everything else is written once.

Public projectNestJS, React, TypeScript, SQLite, Drizzle, Zod, WebSocket, Docker

The problem

Every tournament format (single elimination, double, round robin) has its own rules. Written into the code that propagates results, they repeat everywhere: each new format adds conditions to everything that reads a bracket.

The approach

A format is a pure function of its entrants. It returns the matches to play and the edges saying where each winner and loser goes next. Propagating a result, cascading a correction, computing odds, deciding a tournament is over: everything reads that graph and ignores the format. Adding a format means adding one file.

Live odds

After every result, each entrant's title probability is recomputed and pushed over WebSocket. Elimination formats form an acyclic graph, so one dynamic-programming pass gives an exact answer. Round robin is enumerated exhaustively up to 14 remaining matches, then sampled over 20,000 Monte Carlo trials.

What remains open

No hosted demo: the project runs locally with its seeded data.

The bracket, the standings and the live title odds of an ongoing double elimination
A format is a pure function
Entrantsformat()pure function{ matches, edges }Title oddsexact · Monte CarloWebSocketliveTests217 + 25 + 7computeverify