DEV Community

Rapen
Rapen

Posted on

How I Built "Build a Footballer": A Deterministic Season Simulator for a Card Game

Build a footballer — that one phrase is the whole product, and it's also a surprisingly good design constraint. I wanted a web game where you create your own player from a draft, then watch that player live out a full season. This post is about the two decisions that made it work: a 12-trait draft that gives every build a distinct identity, and a season simulator that's deliberately deterministic so the leaderboard stays fair and the stories stay shareable.

The core loop: build a footballer by stealing traits

To build a footballer, you don't fill in a stat sheet — you draft one. The loop:

  1. Spin a club-era pool.
  2. See 3–5 players from that pool.
  3. Pick one, steal a single trait.
  4. Repeat 12 times.

After 12 rounds you have a card that's genuinely yours. The draft is the hook; the season is the payoff.

Why 12 traits instead of 6

Most "create your own player" games use a compact stat set (speed, shooting, passing, dribbling, defending, physical). That converges fast — everyone ends up with the same meta build. We went wider, with 12 independent axes:

PAC FIN SHO PAS VIS DRI
CRS DEF PHY STA WF CLU

Pace, Finishing, Shooting, Passing, Vision, Dribbling, Crossing, Defending, Physical, Stamina, Weak Foot, and Club. With 12 independent axes, a winger, a target man, and a regista at the same OVR all feel genuinely different. And CLU (club) is the curveball — it carries club/era context that feeds the narrative engine below.

The season simulator: deterministic, so the build is the story

A full career is 38 league matches plus cup competitions, producing trophies, goals, assists, and signature moments — not just a stat sheet.

The deliberate design choice: results are deterministic. Given the card's traits and a seed, the same build always produces the same season:

season(traits, seed) -> { table, goals, assists, moments }

Why not random? Because when you let people build a footballer and compete, randomness breaks three things:

  • Fair leaderboards. Identical builds should get identical seasons — otherwise ranking ranks luck, not skill.
  • Testability. Determinism means I can assert exact outcomes in CI. The hardest part of game dev is testing; this makes it a non-issue.
  • Shareable stories. "My striker scored 30" only means something if it's reproducible for the same build.

Seed policy: one engine, two modes

Deterministic doesn't mean identical for everyone. It's controlled by seed policy:

  • Daily Challenge pins everyone to the same seed → fair shared leaderboard.
  • Free play uses a per-player seed → everyone can build a footballer their own way.

Same engine, one knob. That's how a single simulator serves both a competition and a sandbox.

Takeaways

  • Reproducibility beats drama when your game has a leaderboard/social layer.
  • Seed policy is a feature, not an implementation detail.
  • Granular trait axes give a deterministic engine real input variety.

Try it

The whole thing is free to play. Build a footballer, steal some traits, and sim a season:

👉 buildafootballer.co (https://buildafootballer.co/)

I'm curious how other devs handle the randomness-vs-fairness tradeoff in community games. What do you seed, and what do you leave to chance?

Top comments (0)