Point the Overtime fixtures comment at the real solver: GAMES-NEW.md Appendix A and its TypeScript port in server/src/engines/defuse.ts, not the missing tools/reference/overtime_solver.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
304 lines
15 KiB
YAML
304 lines
15 KiB
YAML
id: tick-tock-overtime
|
|
engine: defuse
|
|
category: co-op
|
|
title: "Tick Tock: Overtime"
|
|
tagline: Six modules. Four levels. A manual that fights back.
|
|
estimatedMinutes: 20
|
|
difficulty: 4
|
|
players: { min: 2, max: 2 }
|
|
theme: { primary: "#ff3b30", accent: "#00d1ff", background: "#0a0a0a", headingFont: "JetBrains Mono" }
|
|
roles:
|
|
A:
|
|
name: Technician
|
|
blurb: You see the device. You can't see the manual. Describe everything, exactly.
|
|
B:
|
|
name: Expert
|
|
blurb: You have the manual. You can't see the device. Ask the right questions, in the right order.
|
|
intro: |
|
|
Remember the training device? This is the sequel. Someone upgraded it.
|
|
New modules, new rules, indicator lights, and a manual written by someone who clearly hates couples.
|
|
|
|
**Technician:** start by reading out the serial number, battery count, and every indicator (lit and unlit).
|
|
**Expert:** you'll need all of it.
|
|
|
|
# ---------- Device definition ----------
|
|
ruleset: overtime # which manual the server's solver implements (server/src/engines/defuse.ts)
|
|
device:
|
|
serial:
|
|
length: 6
|
|
alphabet: "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789" # last char is ALWAYS a digit
|
|
batteries: { min: 0, max: 4 }
|
|
indicators:
|
|
labels: [LUV, HUG, BAE, XOX, DTE]
|
|
count: { min: 1, max: 3 } # each shown indicator is randomly lit or unlit
|
|
|
|
levels:
|
|
- id: lvl1
|
|
title: Warm-up (that isn't)
|
|
timeSeconds: 240
|
|
modules: [wires, button, keypad]
|
|
keyName: Spark Key
|
|
- id: lvl2
|
|
title: Words & Waves
|
|
timeSeconds: 270
|
|
modules: [wires, passwords, morse]
|
|
keyName: Frequency Key
|
|
- id: lvl3
|
|
title: Say It Back
|
|
timeSeconds: 300
|
|
modules: [wires, button, passwords, simon]
|
|
keyName: Echo Key
|
|
- id: lvl4
|
|
title: Overtime
|
|
timeSeconds: 360
|
|
strikesOverride: 2 # only 2 strikes on this level
|
|
modules: [wires, button, keypad, passwords, morse, simon]
|
|
keyName: Overtime Key
|
|
|
|
strikes: { max: 3, speedUpPerStrike: 0.25 }
|
|
|
|
# ---------- Module generation ----------
|
|
modules:
|
|
wires:
|
|
count: { min: 3, max: 6 }
|
|
colors: [red, blue, yellow, green, white, black]
|
|
# Technician: wires top to bottom, colour swatch + colour NAME label. Action { type: "cut", index }
|
|
button:
|
|
labels: [HOLD, PRESS, ABORT, DETONATE, LOVE]
|
|
colors: [red, blue, white, yellow]
|
|
stripColors: [blue, white, yellow, red]
|
|
# Strip only shown WHILE holding. Actions: tap | hold → release { timerText }
|
|
keypad:
|
|
symbols:
|
|
heart: "♥ Heart"
|
|
star: "★ Star"
|
|
moon: "☾ Moon"
|
|
sun: "☀ Sun"
|
|
club: "♣ Club"
|
|
flower: "✿ Flower"
|
|
key: "⚷ Key"
|
|
umbrella: "☂ Umbrella"
|
|
plane: "✈ Plane"
|
|
music: "♫ Music note"
|
|
anchor: "⚓ Anchor"
|
|
crown: "♛ Crown"
|
|
diamond: "♦ Diamond"
|
|
spade: "♠ Spade"
|
|
bolt: "⚡ Bolt"
|
|
cloud: "☁ Cloud"
|
|
columns:
|
|
- [heart, star, moon, sun, club, flower, key]
|
|
- [umbrella, heart, plane, music, star, anchor, crown]
|
|
- [diamond, sun, spade, umbrella, flower, music, bolt]
|
|
- [anchor, spade, club, plane, moon, diamond, key]
|
|
- [crown, bolt, heart, diamond, plane, sun, cloud]
|
|
- [cloud, music, key, spade, club, crown, star]
|
|
# Generator: pick a column, pick 4 of its symbols, shuffle. Re-roll if any OTHER column also
|
|
# contains all 4 (validated: no 4-subset of these columns is ambiguous).
|
|
passwords:
|
|
columnsCount: 5
|
|
lettersPerColumn: 6
|
|
words: [ADORE, ANGEL, BLISS, BLUSH, CANDY, CHARM, CRUSH, DANCE, DREAM, FLAME, FLIRT, HEART,
|
|
HONEY, LOVER, MATCH, PEACH, RINGS, ROSES, SMILE, SPARK, SUGAR, SWEET, TEDDY, TRUST,
|
|
TULIP, UNITY, WALTZ, BLOOM, CHOSE, PEARL, VOWED, QUEEN]
|
|
# Technician sees 5 columns with up/down arrows; each column cycles through 6 letters.
|
|
# Generator: pick a target word; fill each column with its letter + 5 random letters; re-roll until
|
|
# EXACTLY ONE word in the list can be formed. Action { type: "submit", word }
|
|
morse:
|
|
# Technician sees a blinking light (reuse the signal renderer, §6.3) and a frequency dial
|
|
# from 3.500 to 3.600 MHz in 0.001 steps + a TX button. Action { type: "transmit", frequency }
|
|
words:
|
|
HUG: "3.505"
|
|
KISS: "3.515"
|
|
LOVE: "3.522"
|
|
DATE: "3.532"
|
|
RING: "3.535"
|
|
ROSE: "3.542"
|
|
WINE: "3.545"
|
|
DUET: "3.552"
|
|
DANCE: "3.555"
|
|
HEART: "3.565"
|
|
SWEET: "3.572"
|
|
HONEY: "3.575"
|
|
CUDDLE: "3.582"
|
|
SPARK: "3.592"
|
|
VOWS: "3.595"
|
|
BLISS: "3.600"
|
|
simon:
|
|
colors: [red, blue, green, yellow]
|
|
stages: { min: 3, max: 5 }
|
|
# Device flashes a sequence; each stage adds one flash. Technician presses the MAPPED colours
|
|
# for the whole sequence so far. Mapping depends on (serial has a vowel) and CURRENT strike count.
|
|
# Action { type: "press", color }
|
|
|
|
# ---------- The manual (shown ONLY to the Expert) ----------
|
|
manual: |
|
|
# Defusal Manual: Overtime Edition
|
|
|
|
**Before anything else, ask for:** serial number · battery count · every indicator and whether it's **lit**.
|
|
A "vowel" means A, E, I, O or U.
|
|
|
|
---
|
|
|
|
## Module: Wires (3 to 6 wires)
|
|
Wires are numbered **top to bottom** from 1. Cut exactly one. Find the section for the number of wires,
|
|
then use the **first** rule that applies.
|
|
|
|
**3 wires**
|
|
1. If all three wires are **different colours** → cut the **second** wire.
|
|
2. If there are **two or more blue** → cut the **first blue** wire.
|
|
3. If the serial contains a **vowel** → cut the **last** wire.
|
|
4. Otherwise → cut the **first** wire.
|
|
|
|
**4 wires**
|
|
1. If there is **exactly one green** wire and **2 or more batteries** → cut the **green** wire.
|
|
2. If the **first and last** wires are the **same colour** → cut the **third** wire.
|
|
3. If there are **no white** wires → cut the **second** wire.
|
|
4. Otherwise → cut the **last white** wire.
|
|
|
|
**5 wires**
|
|
1. If there are **more black than red** wires → cut the **first black** wire.
|
|
2. If the serial's **last digit is odd** → cut the **fourth** wire.
|
|
3. If there is **exactly one yellow** → cut the wire **directly after** the yellow (if yellow is last, cut the **first**).
|
|
4. Otherwise → cut the **second** wire.
|
|
|
|
**6 wires**
|
|
1. If there's a **lit LUV** indicator → cut the **sixth** wire.
|
|
2. If there are **exactly three red** wires → cut the **third red** wire.
|
|
3. If there are **no yellow** wires → cut the **third** wire.
|
|
4. Otherwise → cut the **fifth** wire.
|
|
|
|
---
|
|
|
|
## Module: The Button
|
|
First rule that applies:
|
|
1. **Blue** button that says **ABORT** → **hold**.
|
|
2. **More than 1 battery** and says **DETONATE** → **tap**.
|
|
3. **White** button and a **lit BAE** → **hold**.
|
|
4. **More than 2 batteries** and a **lit HUG** → **tap**.
|
|
5. **Yellow** button → **hold**.
|
|
6. **Red** button that says **HOLD** → **tap**.
|
|
7. Otherwise → **hold**.
|
|
|
|
**If holding**, a strip lights up. Release when the timer shows this digit **anywhere**:
|
|
Blue → **4** · White → **1** · Yellow → **5** · Red → **3**
|
|
|
|
---
|
|
|
|
## Module: Keypad
|
|
Exactly one column below contains all four symbols on the device.
|
|
Press them in the order they appear **top to bottom** in that column.
|
|
|
|
| 1 | 2 | 3 | 4 | 5 | 6 |
|
|
|---|---|---|---|---|---|
|
|
| ♥ Heart | ☂ Umbrella | ♦ Diamond | ⚓ Anchor | ♛ Crown | ☁ Cloud |
|
|
| ★ Star | ♥ Heart | ☀ Sun | ♠ Spade | ⚡ Bolt | ♫ Music note |
|
|
| ☾ Moon | ✈ Plane | ♠ Spade | ♣ Club | ♥ Heart | ⚷ Key |
|
|
| ☀ Sun | ♫ Music note | ☂ Umbrella | ✈ Plane | ♦ Diamond | ♠ Spade |
|
|
| ♣ Club | ★ Star | ✿ Flower | ☾ Moon | ✈ Plane | ♣ Club |
|
|
| ✿ Flower | ⚓ Anchor | ♫ Music note | ♦ Diamond | ☀ Sun | ♛ Crown |
|
|
| ⚷ Key | ♛ Crown | ⚡ Bolt | ⚷ Key | ☁ Cloud | ★ Star |
|
|
|
|
---
|
|
|
|
## Module: Passwords
|
|
The Technician can cycle five letter columns. Exactly **one** word below can be spelled.
|
|
Find it and have them submit it.
|
|
|
|
ADORE · ANGEL · BLISS · BLOOM · BLUSH · CANDY · CHARM · CHOSE · CRUSH · DANCE · DREAM
|
|
FLAME · FLIRT · HEART · HONEY · LOVER · MATCH · PEACH · PEARL · QUEEN · RINGS · ROSES
|
|
SMILE · SPARK · SUGAR · SWEET · TEDDY · TRUST · TULIP · UNITY · VOWED · WALTZ
|
|
|
|
*Tip: ask for the letters in column 1 first, then 2. That usually narrows it down fast.*
|
|
|
|
---
|
|
|
|
## Module: Morse Light
|
|
The light blinks a word in Morse, over and over, with a long pause between repeats.
|
|
Short = dot · Long = dash. Decode the word, then have them tune and transmit:
|
|
|
|
| Word | MHz | Word | MHz |
|
|
|------|-----|------|-----|
|
|
| HUG | 3.505 | DUET | 3.552 |
|
|
| KISS | 3.515 | DANCE | 3.555 |
|
|
| LOVE | 3.522 | HEART | 3.565 |
|
|
| DATE | 3.532 | SWEET | 3.572 |
|
|
| RING | 3.535 | HONEY | 3.575 |
|
|
| ROSE | 3.542 | CUDDLE | 3.582 |
|
|
| WINE | 3.545 | SPARK | 3.592 |
|
|
| BLISS | 3.600 | VOWS | 3.595 |
|
|
|
|
`A .- B -... C -.-. D -.. E . F ..-. G --. H .... I .. J .--- K -.- L .-.. M --`
|
|
`N -. O --- P .--. Q --.- R .-. S ... T - U ..- V ...- W .-- X -..- Y -.-- Z --..`
|
|
|
|
---
|
|
|
|
## Module: Say It Back (Simon)
|
|
The device flashes colours. The Technician must press the **mapped** colour for every flash so far.
|
|
⚠️ The mapping **changes with the strike count**. Re-check after every strike.
|
|
|
|
**Serial HAS a vowel**
|
|
| Strikes | Red → | Blue → | Green → | Yellow → |
|
|
|---------|-------|--------|---------|----------|
|
|
| 0 | Blue | Red | Yellow | Green |
|
|
| 1 | Yellow | Green | Blue | Red |
|
|
| 2 | Green | Red | Yellow | Blue |
|
|
|
|
**Serial has NO vowel**
|
|
| Strikes | Red → | Blue → | Green → | Yellow → |
|
|
|---------|-------|--------|---------|----------|
|
|
| 0 | Blue | Yellow | Green | Red |
|
|
| 1 | Red | Blue | Yellow | Green |
|
|
| 2 | Yellow | Green | Blue | Red |
|
|
|
|
# ---------- Solver fixtures (MUST pass as unit tests) ----------
|
|
# Generated from the reference solver (GAMES-NEW.md, Appendix A), which implements the manual
|
|
# above exactly. Its TypeScript port is the `overtime` ruleset in server/src/engines/defuse.ts.
|
|
fixtures:
|
|
wires:
|
|
- {"serial": "TK4L82", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "blue", "yellow"], "expect": {"type": "cut", "index": 2}}
|
|
- {"serial": "QX7M35", "batteries": 0, "indicators": {"lit": [], "unlit": []}, "wires": ["blue", "red", "blue"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "ZP2R44", "batteries": 2, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "red", "white"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "BC2D48", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "red", "green"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "AB9C11", "batteries": 2, "indicators": {"lit": [], "unlit": []}, "wires": ["green", "red", "blue", "white"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "LM3N06", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["blue", "red", "yellow", "blue"], "expect": {"type": "cut", "index": 3}}
|
|
- {"serial": "RT5W22", "batteries": 0, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "yellow", "red", "black"], "expect": {"type": "cut", "index": 2}}
|
|
- {"serial": "HK8P71", "batteries": 0, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "white", "blue", "white"], "expect": {"type": "cut", "index": 4}}
|
|
- {"serial": "XY3Z45", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["black", "black", "red", "blue", "white"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "PQ7R18", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "blue", "yellow", "white", "green"], "expect": {"type": "cut", "index": 4}}
|
|
- {"serial": "PQ7R12", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "blue", "yellow", "white", "green"], "expect": {"type": "cut", "index": 4}}
|
|
- {"serial": "PQ7R12", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "blue", "white", "white", "yellow"], "expect": {"type": "cut", "index": 1}}
|
|
- {"serial": "ST4V20", "batteries": 1, "indicators": {"lit": [], "unlit": []}, "wires": ["red", "white", "blue", "green", "black"], "expect": {"type": "cut", "index": 2}}
|
|
- {"serial": "BC1D20", "batteries": 3, "indicators": {"lit": ["LUV"], "unlit": []}, "wires": ["red", "red", "red", "blue", "white", "green"], "expect": {"type": "cut", "index": 6}}
|
|
- {"serial": "BC1D20", "batteries": 3, "indicators": {"lit": [], "unlit": ["LUV"]}, "wires": ["red", "blue", "red", "white", "red", "green"], "expect": {"type": "cut", "index": 5}}
|
|
- {"serial": "BC1D20", "batteries": 3, "indicators": {"lit": [], "unlit": []}, "wires": ["blue", "blue", "white", "green", "black", "red"], "expect": {"type": "cut", "index": 3}}
|
|
- {"serial": "BC1D20", "batteries": 3, "indicators": {"lit": [], "unlit": []}, "wires": ["yellow", "blue", "white", "green", "black", "red"], "expect": {"type": "cut", "index": 5}}
|
|
button:
|
|
- {"batteries": 0, "indicators": {"lit": [], "unlit": []}, "label": "ABORT", "color": "blue", "strip": "yellow", "expect": {"type": "hold", "releaseDigit": 5}}
|
|
- {"batteries": 2, "indicators": {"lit": [], "unlit": []}, "label": "DETONATE", "color": "red", "strip": "blue", "expect": {"type": "tap"}}
|
|
- {"batteries": 1, "indicators": {"lit": ["BAE"], "unlit": []}, "label": "LOVE", "color": "white", "strip": "red", "expect": {"type": "hold", "releaseDigit": 3}}
|
|
- {"batteries": 3, "indicators": {"lit": ["HUG"], "unlit": []}, "label": "PRESS", "color": "red", "strip": "white", "expect": {"type": "tap"}}
|
|
- {"batteries": 0, "indicators": {"lit": [], "unlit": []}, "label": "PRESS", "color": "yellow", "strip": "blue", "expect": {"type": "hold", "releaseDigit": 4}}
|
|
- {"batteries": 1, "indicators": {"lit": [], "unlit": []}, "label": "HOLD", "color": "red", "strip": "white", "expect": {"type": "tap"}}
|
|
- {"batteries": 1, "indicators": {"lit": [], "unlit": ["HUG"]}, "label": "LOVE", "color": "white", "strip": "red", "expect": {"type": "hold", "releaseDigit": 3}}
|
|
keypad:
|
|
- {"symbols": ["star", "flower", "heart", "sun"], "expect": ["heart", "star", "sun", "flower"]}
|
|
- {"symbols": ["spade", "plane", "anchor", "moon"], "expect": ["anchor", "spade", "plane", "moon"]}
|
|
- {"symbols": ["music", "umbrella", "diamond", "sun"], "expect": ["diamond", "sun", "umbrella", "music"]}
|
|
- {"symbols": ["cloud", "crown", "bolt", "plane"], "expect": ["crown", "bolt", "plane", "cloud"]}
|
|
- {"symbols": ["star", "key", "club", "crown"], "expect": ["key", "club", "crown", "star"]}
|
|
passwords:
|
|
- {"columns": ["XAPUDI", "RVCSEX", "TGAHRQ", "RASIYZ", "CDGKYL"], "expect": "PEARL"}
|
|
- {"columns": ["BZRWXO", "GLTUAS", "YHCDLJ", "FVTGIL", "OFZIUM"], "expect": "WALTZ"}
|
|
- {"columns": ["KYBZTH", "UPOMRG", "SLXUMN", "SEFZUD", "ROTIAQ"], "expect": "TRUST"}
|
|
morse:
|
|
- {"signal": "..../..-/--.", "expect": {"word": "HUG", "frequency": "3.505"}}
|
|
- {"signal": "...././.-/.-./-", "expect": {"word": "HEART", "frequency": "3.565"}}
|
|
- {"signal": "-.../.-../../.../...", "expect": {"word": "BLISS", "frequency": "3.600"}}
|
|
- {"signal": "...-/---/.--/...", "expect": {"word": "VOWS", "frequency": "3.595"}}
|
|
simon:
|
|
- {"serial": "TK4E82", "strikes": 0, "flashes": ["red", "green", "yellow"], "expect": ["blue", "yellow", "green"]}
|
|
- {"serial": "TK4E82", "strikes": 1, "flashes": ["red", "green", "yellow"], "expect": ["yellow", "blue", "red"]}
|
|
- {"serial": "ZP2R44", "strikes": 0, "flashes": ["blue", "blue", "green", "yellow"], "expect": ["yellow", "yellow", "green", "red"]}
|
|
- {"serial": "ZP2R44", "strikes": 2, "flashes": ["yellow", "red", "green"], "expect": ["red", "yellow", "blue"]}
|