← Back to the gamebug or idea?Terrapin Trail//Code BibleIIhow the game works, archive to van
Reel 15 · 6 min read

Changing the rules

How a few sliders change the whole game, and how a rule set fits inside a hashtag.

Game DNA lets a player change the rules before a run: how fast the van burns gas, how chaotic the road is, whether selling tapes hurts your reputation. Here's how a few sliders change a whole game.

The rules are a list

All the rules live in one list. Each one says what it's called, its range, and its normal value:

●dna.py : 16–27trace ↗
16RULES: list[dict[str, Any]] = [
17    {
18        "id": "code", "name": "Taper's code", "unit": " Cred per tape sold", "min": 0, "max": 10, "step": 1, "def": 0,
19        "isNew": True,
20        "hint": "Old-school tapers traded, never sold. Lot Cred you lose for each tape you sell. The game as built has none.",
21    },
22    {"id": "gas", "name": "Gas guzzling", "unit": "x", "min": 0.5, "max": 2, "step": 0.25, "def": 1,
23     "hint": "How fast the van burns gas between shows."},
24    {"id": "chaos", "name": "Road chaos", "unit": "x", "min": 0, "max": 2, "step": 0.25, "def": 1,
25     "hint": "How many surprises hit you on each drive: cops, flat tires, strangers, stews."},
26    {"id": "wear", "name": "Van wear", "unit": "x", "min": 0.5, "max": 2, "step": 0.25, "def": 1,
27     "hint": "How hard the road is on the van."},
The rule list. The browser draws one slider per entry, and the game reads the values.

Concept: "single source of truth". When the same information is needed in several places, keep it in one place and have everything read from there. Here the browser, the server and the game all use this one list, so they can't disagree.

Turning sliders into a short code

To put a rule set in a hashtag, the slider positions are packed into a short code. Ready-made rule sets use their name, like "HardRoad". Any other mix becomes something like "X3K9":

●dna.py : 72–86trace ↗
72def encode(values: dict) -> str:
73    """Rule values -> a code: a preset name, or a short base-36 string of slider positions."""
74    vals = normalize(values)
75    for name, p in PRESETS.items():
76        if vals == normalize(p["values"]):
77            return name
78    n = 0
79    for r in RULES:
80        n = n * _positions(r) + round((vals[r["id"]] - r["min"]) / r["step"])
81    s = ""
82    while n:
83        n, d = divmod(n, 36)
84        s = _ALPHA[d] + s
85    # A leading "X" marks a custom code so it can never collide with a preset name.
86    return "X" + (s or "0")
If the sliders match a ready-made set, use its name. Otherwise turn the positions into one number and write it in base 36 (digits plus letters), so it's short.

Concept: "encoding". Encoding means writing information in a different form without losing any of it. The code 'X3K9' can be decoded back into the exact slider positions, which is why a friend who clicks your link gets your exact rules.

Where the game uses them

The game reads the rules once when it starts, and each rule changes one small spot. For example, the gas a drive needs:

●assets/game/game.js : 1481–1481trace ↗
1481    var gas = Math.ceil(next.miles / 70 * DNA.gas); // TT-DNA gas guzzling
Normally a drive needs one gas per 70 miles. Gas guzzling multiplies that.

Taper's code is a brand-new rule. Real tapers traded tapes and never sold them, so when this rule is on, selling a tape costs you reputation:

●assets/game/game.js : 43–48trace ↗
43  function tapersCode(s, n) {
44    if (!DNA.code) return "";
45    var hit = Math.round(DNA.code * n);
46    s.cred = clamp(s.cred - hit, 0, 100);
47    return " The tapers saw that. -" + hit + " Lot Cred.";
48  }
If the rule is on, take away some Lot Cred for each tape sold.
The ideas to keep
  • All the rules are in one list, a single source of truth.
  • A rule set is encoded into a short code that rides on the hashtag.
  • Each rule changes one small spot in the game; every rule set has its own leaderboard.