Stacked ▲ Reversed 2048 — Game Design Spec

Type: Product Requirements Document Status: Draft for review Series: Do villain things (sibling of minelayer, ghost-squad, saboteur) Deliverable target: single offline HTML file

1. Background and Goals

Concept. Stacked is a reversed 2048: the player is the placer, choosing where each new tile appears on the 4×4 grid, while an AI opponent — the Slider — slides and merges tiles to survive and build toward 2048. The player wins by making the board reach a state with no valid moves: full and no adjacent same-value tiles. Where the original asks "merge to 2048," the reversal asks "stack the board until it chokes."

Design lineage. This candidate passed all six filters of the series' selection process (dev/docs/selection-spec.html, an internal design doc that is not published with the games):

Goals (observable outcomes).

2. Product Contract

ElementDefinition
Primary userA casual player in a browser; solo only
TriggerOpening the HTML file; boots to TITLE with no external resources
Core jobPlace tiles that force the AI Slider into a no-valid-moves state
Completion (tier cleared)The board has no valid moves: full, and no adjacent tiles share a value
FailureNone by design (mirror of the original's absent win state — the original player always eventually loses). A passive player never wins but never loses; they simply don't clear the tier. Quitting is always available. See FR-03.
Trust boundariesFully local: no network calls, no external assets, no accounts; progression and best scores only in localStorage

3. Scope

P0 — required for the complete game P0

P1 — valuable, not blocking P1

Explicitly excluded OUT

Rejected during design: a "turn budget" meter (player has N turns to win; exceeding it = player loses). Rejected as foreign to 2048 culture. Termination instead comes from the original's own vocabulary: the board-choke condition. A passive player never loses but never progresses — disengagement is its own failure, identical to Saboteur's design.

4. Game Model

4.1 Objects

ObjectCanonical definition
GridStandard 4×4 2048 playfield, original rules: slide in one of 4 directions (up/down/left/right); same-value adjacent tiles merge into their sum; each slide may produce at most one merge per tile per direction.
TileA cell occupant with a power-of-2 value (2, 4, 8, … 2048+). Tiles appear in the original's color palette. The two opening tiles spawn at the original's native 90/10 ratio (2 vs 4); player-placed tiles come from the Rack (SR-2).
Placer (player)Chooses which available value from the Rack to place, and which empty cell receives it. One verb: place — pick a value, pick a cell.
Slider (AI)The opponent. Slides tiles in the direction that maximizes its heuristic score (SR-4). Visible "thinking" delay before each slide; tier-scaled search depth.
TurnThe match's atomic unit: one player placement + one AI slide. The turn count is the match's score (golf scoring — fewer turns to choke = better). Turn is the analog of Saboteur's beat.
ChokeThe terminal state: the board is full (no empty cells) AND no adjacent tiles share a value (no valid slide produces a merge). This is the player's win condition.
RackThe player's fixed set of three value slots — 2, 4, 8 — each with a cooldown clock measured in player turns (SR-2). A slot is placeable only when its clock reads 0; placing a value restarts that slot's clock at its tier cooldown. Clocks tick down once per completed turn. Value 2 is always placeable (cooldown 0), so the player is never without a legal placement. Cooldown state is public information — the Slider's search reads it (SR-4).
TierA fixed-AI-difficulty match configuration. Higher tier = deeper AI search = harder to choke. Three tiers: Beginner, Intermediate, Expert (SR-3).

4.2 Match state machine (canonical)

TITLE ──▶ TIER SELECT ──(pick any tier — all open)──▶ READY (~1.5 s) ──▶ PLAY ▲ ▲ │ │ │ ┌── Board chokes ──▶ CLEARED ──▶ SUMMARY └──(Esc menu)────┴────────┤ (save best for tier) │──▶ TIER SELECT │ └──▶ next tier READY PLAY ◀──(Esc / blur)──▶ PAUSED: all turns, AI search, and placement frozen PLAY ──(Q / quit)──▶ TIER SELECT (match abandoned; no score recorded)

There is no LOSS state by design (§2). The only terminal state of PLAY is CLEARED (board choke) and player-initiated quit. If the AI survives indefinitely (Expert tier against a struggling player), the player simply doesn't clear the tier — they should try a lower tier.

5. Functional Requirements

FR-012048-faithful presentation

FR-02Difficulty tiers and progression

FR-03Match loop (place-then-slide)

AspectRule
Ready phase~1.5 s countdown; grid empty; two opening tiles appear (value 2 at 90%, 4 at 10%, random positions — the original's starting condition). No input accepted.
Player phaseYOUR RACK shows the three value slots with their cooldown state (per SR-2); the selected available slot is highlighted. The player picks a value (click an available rack tile or 1/2/3) and clicks an empty cell (or navigates with arrow keys + Space/Enter). The chosen tile appears in the chosen cell and that slot's cooldown clock starts. Turn counter increments.
AI phaseAfter a visible "thinking" delay (SR-3), the Slider evaluates the board and chooses a slide direction. Tiles slide and merge per 2048 rules. The slide animation plays.
Win checkAfter the AI slide, check: is the board full with no valid merges? If yes → CLEARED. If no → all rack cooldown clocks tick down one turn (SR-2), return to Player phase.
No lose stateA match continues until the board chokes or the player quits (Q → TIER SELECT, nothing recorded). If the AI reaches 2048, the game continues — it is a milestone, not game-over. Tiles past 2048 are harder to merge, so the board naturally chokes at high values.
ReplaySUMMARY offers: retry this tier (R), TIER SELECT (Esc).
ExceptionsTab hidden or window blurred during PLAY → auto-PAUSED (SR-5). If the AI has only one valid direction, it takes it immediately (no thinking delay for a forced move).

FR-04Placement controls

Interactive demo — FR-04 placement / FR-03 turn cycle

Pick an available value from your rack, then click an empty cell to place it. The Slider (a simple 1-ply AI in this demo) will respond. Choke the board to win. Demo uses a simplified AI and a Beginner-style cooldown rack; the full game uses tier-scaled expectimax (SR-4) and tier-scaled racks (SR-2).

Turn: 0 Rack: 248 Highest: —
Pick a rack value, then click an empty cell.
Demo: 1-ply AI (greedy: maximize free cells + merges) · Beginner cooldowns (4: 2 turns, 8: 4 turns). Full game uses expectimax with tier-scaled depth.

FR-05The Slider bot

FR-06Win condition, scoring, and attribution

FR-07Audio

FR-08Responsive layout and touch controls

FR-09Result sharing (community layer, phase 1)

6. Shared Rules

SR-1 · Turn model (canonical)

A turn = one player placement + one AI slide. The turn is the match's atomic unit: turn count is the score (golf — fewer is better), and all tier differences are measured in AI search depth per turn. Pause freezes turns entirely. There is no real-time element — Stacked is purely turn-based, a deliberate contrast to Ghost Squad (real-time action) and Saboteur (beat-timed). The fun is in the placement decision, not in reaction speed.

SR-2 · Rack cooldown supply (canonical)

The player places from a fixed rack of three value slots — 2, 4, 8. Each slot carries a cooldown clock measured in player turns. Placing a value sets its slot's clock to that tier's cooldown length (SR-3); after every completed turn (AI slide), all nonzero clocks tick down by one. A slot is placeable only when its clock reads 0. Value 2's cooldown is 0 at every tier, so the player is never without a legal placement. The value pool {2, 4, 8} is the original's own vocabulary — these are the only tile values the original ever spawns (2 and 4), plus 8 as the natural extension that gives the placer real disruption power at the cost of also feeding the Slider's merges. The two opening board tiles still spawn at the original's native 90/10 ratio, untouched.

Why a rack instead of the original's fixed 90/10 stream? The F2 spike (§9) settled this empirically: with position-only placement (a single predetermined value per turn), an adversarial placer achieves 0% win rate at every tier — the AI merges faster than one tile per turn can clutter a 4×4 board, a fundamental design failure under the spec's own kill criterion. Value choice is the structural fix: it lets the player attack merge chains directly. Free choice of any value was rejected as degenerate (always-8 checkerboards trivialize the game), so the value supply must be gated.

Design history — iid hand → cooldown rack. The first guardrail was a weighted random hand of 3 drawn iid per turn (55/30/15 → 68/24/8 by tier). It passed the spike, but playtesting exposed a presentation flaw: hands frequently contained duplicate values ("I was given three candidates, two of them the same"), which read as noise rather than choice. The fix adopts Saboteur's cooldown pattern: replace the random draw with a deterministic, fully legible supply — fixed slots with visible cooldown clocks. This removes all hand randomness (the player always knows what is available now and when it returns) while preserving the same placement-rate mix through cooldown lengths. A side benefit: the cooldown state is public information, so the AI's search can model the player's options exactly (SR-4) instead of statistically.

SR-3 · Difficulty tier configuration (canonical)

TierAI search depthBlunder rateRack cooldowns {4, 8} (2 always 0)Thinking delayFlavor
Beginner0-ply (reactive: pick best-looking direction now)5%4: 2 turns · 8: 4 turns (rich)~300 msNo lookahead, a rich rack, and the occasional slip — a beatable, human-feeling opponent
Intermediate3-ply expectimax5%4: 2 turns · 8: 10 turns (mixed)~600 msThe AI thinks one full response ahead; placement must anticipate it, but it still blunders now and then
Expert4-ply expectimax5%4: 4 turns · 8: 12 turns (lean)~1000 msDeepest search and the leanest rack, but still prone to occasional tactical slips — sharp, not unbeatable

Per-tier values are fixed, not curve-generated. The Slider's decision quality (heuristic + search model) is identical across tiers — only the search depth, the blunder rate, and the rack cooldowns change. The blunder rate is the fallibility knob (SR-4): a pure optimal expectimax never makes a tactical mistake, which reads as inhuman and demoralizing; a small per-tier probability of picking a suboptimal valid direction gives the player realistic openings without making the AI look broken. Expert keeps depth 4 (the deepest search the ~1000 ms thinking budget allows, ~130–310 ms/slide) deliberately — it is the hard tier and is supposed to plan ahead; what makes it beatable and human is the blunder rate, not a shallower search. The 2025-10 tuning pass addressed playtest feedback that the Slider "plans too many steps ahead and never makes a mistake," and a follow-up concern that Beginner took too long to win. The key discovery: at shallow depth, blunder rate barely affects game length (the base play is already weak) — the real lever for Beginner game length is search depth itself. Beginner was dropped from 1-ply to 0-ply (purely reactive, no lookahead), halving median game length from ~115 to ~59 turns while keeping win rate ~80%. Intermediate kept 3-ply (one full response of lookahead) but its blunder was raised to 5% after depth-3/blunder-3% measured only 35% (below the 40% band floor); 5% brought it to 55%, mid-band. Expert's blunder was raised to 5% after 3% measured 0% for the human placer (below the 10% band floor); 5% brought it to ~20%, mid-band. All values are named constants (AI_DEPTHS, AI_BLUNDER_RATES, AI_THINK_DELAYS_MS, RACK_COOLDOWNS) grouped in the implementation's tuning-constants block. Tuning history: Expert originally stacked a lean iid hand (80/15/5) on top of 4-ply search — 0% placer win rate (0/5), out of band; depth became the sole differentiator under the iid hand. The rack redesign then supplied its own ladder: the first cooldown configs ({4:3, 8:6} Beginner / {4:4, 8:12} both other tiers) under-supplied Beginner (57.5%, below the >80% band) and starved Intermediate's value choice; the shipped ladder above restored the bands. The 2025-03 tuning pass added the blunder-rate ladder (SR-4) to address the "never makes a mistake" complaint. The 2025-10 pass then lowered Beginner 1→0 ply for game length and raised Intermediate and Expert blunder 3→5% for win rate; all three tiers land in their bands (§9.1, §9.4).

SR-4 · AI search model (canonical)

The Slider uses expectimax with controlled fallibility. Max nodes choose the slide direction maximizing the heuristic (monotonicity + smoothness + free tiles + corner bonus, per FR-05). Chance nodes model the player's next placement exactly as the game plays it: over a sampled set of empty cells (top-4 by adjacency/centrality for performance, AI_MAX_SAMPLED_CELLS), the value placed is the worst (for the AI) value among the rack slots currently off cooldown — and placing a value in the search consumes that slot's cooldown exactly as the real game does. The cooldown clocks are public information, so the model is exact, not statistical: each chance node first ticks the clocks down one turn (one turn elapses), collects the available values, and scores the minimum over them. The two nonzero clocks are packed into the search state (rackEncode, 4 bits each — all cooldowns stay ≤ 15) and into the transposition-table key (board, depth, clocks), so identical boards with different rack states are never confused. Search depth is tier-scaled (SR-3).

The search itself is deterministic and always returns the optimal direction for its horizon. Fallibility is applied as a post-search override at the root only: with per-tier probability (SR-3), the Slider discards the optimal direction and uniformly picks one of the other valid directions. This keeps expectimax pure (tests and the F2-spike harness stay reproducible) while making the in-game Slider human — it still plans ahead, but occasionally makes a clear tactical mistake, giving the player openings rather than always playing a perfect game. A pure optimal opponent that never blunders is the anti-pattern the series avoids (Saboteur and Ghost Squad both give their bots a fallible, personality-driven mistake layer).

Why expectimax with a worst-available-value model, not uniform-random or minimax? Uniform-random value placement (the original AI assumption) is simply wrong here — the player picks the worst value they can legally place, and modeling them as random makes the AI suicidally optimistic. Full minimax (worst cell AND worst value with certainty) overstates the player: even at maximum threat the player can only place what the rack currently supplies — an 8 on cooldown is an 8 the AI need not fear. The exact worst-available-value model is therefore the honest one: it credits the player with every legal option and no illegal ones. (The earlier iid-hand version statistically modeled the worst of a 3-draw; the rack made the supply deterministic, so the model became exact.) This is the same structural honesty Ghost Squad's bots use: model the player's actual mechanism, no stronger and no weaker.

SR-5 · Pause and focus

Esc toggles PAUSED; turns, AI search, and placement freeze. Window blur or tab hidden forces PAUSED. PAUSED dims the grid and shows controls; no state is lost.

SR-6 · Persistence

Stored in localStorage: per-tier best turn count, mute preference, last played tier. Storage unavailable → session-only, no error surfaced.

7. Exceptions and Boundaries

CaseHandling
Board full before player's turn (AI's last slide filled it)Win check runs without player placement. If no valid merges → CLEARED. If merges exist → the AI's slide was invalid (should not happen — the AI checks validity before sliding); treated as a no-op and the player places normally.
Only one empty cell at player's turnPlayer always places manually — the value choice (2/4/8) is the decisive move of the game and is never made for them. No code path may auto-place on the player's behalf. (An earlier draft auto-placed at one empty cell left; it was removed as a defect — it stole the kill shot and could hand the bot a saving 2.)
AI has no valid slide directionBoard choke — CLEARED. The Slider never passes; if it can't slide, the player wins.
AI reaches 2048HUD banner shown; game continues. Tiles past 2048 are harder to merge, naturally leading toward choke.
Player clicks a filled cellInput ignored; no penalty. The cell flashes red briefly to indicate invalid.
Player never places (idle)Turn does not advance. The player must place to proceed. There is no timeout — Stacked is turn-based, not timed. Idleness yields no score and no progress, identical to Saboteur's design.
localStorage blockedSession-only best scores, no error surfaced (FR-06)
Pick in the same instant as AI slide finishPlayer input is timestamped; if the AI is still thinking, the input is queued and applied when the AI finishes. Turn-based: no real-time conflicts.

8. Open Questions and Risks

9. Testing and Difficulty Validation (F2 Spike Plan)

The F2 spike is the make-or-break validation for this design. Its purpose: determine whether an adversarial tile placer can force a board choke against an expectimax-optimal Slider, and at what rate. The methodology mirrors Ghost Squad's upper-bound simulation and Saboteur's headless scenario tests.

9.1 Upper-bound simulation (can the placer win?)

Purpose: verify that a strategic tile placer can force a board choke against a competent AI Slider. Record all turns, measure win rates, and evaluate whether a real player could repeat the performance.

Method: simulate an adversarial placer that, each turn, evaluates every (available rack value × empty cell) pair and places the combination that minimizes the Slider's post-slide heuristic score (i.e., the most disruptive placement). The Slider responds with its tier-scaled expectimax search. Runs seeded deterministically via the game's own RNG. Record: win/loss (choke/no-choke), turn count, highest tile reached, placement position distribution, and placed-value distribution.

Note: the §9.1 table below reflects the greedy (upper-bound) placer against an earlier tuning config (depths [1,2,4], blunders [3,4,3]%). The current config (SR-3: depths [0,3,4], blunders [5,5,5]%) is validated by the human-placer simulation in §9.4 — all three tiers land in their bands. The greedy placer would measure higher win rates than §9.4 across the board.

TierAI depthBlunderRack cooldowns {4, 8}Placer strategyRunsTarget win rateMeasured win rate
Beginner1-ply3%2 / 4 (rich)Greedy: minimize AI heuristic80>80%81.3% (65/80), ~107 avg turns — PASS
Intermediate2-ply4%2 / 10 (mixed)Greedy: minimize AI heuristic2040–70%65.0% (13/20), ~165 avg turns — PASS
Expert4-ply3%4 / 12 (lean)Greedy: minimize AI heuristic5*10–40%~25–35% (estimated; 5-run batch exceeded time budget — see note) — PASS

Kill criterion (history): the first spike used position-only placement (a single system-drawn value per turn, 90/10) and recorded 0% placer win rate at every tier, even at Beginner — below the 50% fundamental-failure line. The placer simply cannot out-clutter a merging AI on a 4×4 board without value control. Value-supply mechanics (SR-2) are the direct structural fix. Two further tuning rounds are documented in SR-3's tuning history: the iid-hand era (Expert's lean hand measured 0% — retuned) and the rack era's first cooldown configs (Beginner 57.5%, under-band — enriched to the shipped ladder). *Expert measurement note: the 2025-03 tuning pass added a per-tier blunder rate (SR-4) that the greedy placer does not anticipate — the placer evaluates each placement assuming the Slider responds optimally. This makes the spike a conservative (pessimistic) measure of the placer's win rate: a real human sees and exploits the Slider's blunders, so actual human win rates are expected to be higher than the spike reports. The Expert 5-run batch at depth 4 exceeded the measurement time budget (depth-4 expectimax on near-full boards is pathologically slow); the 25–35% estimate is derived from the pre-blunder baseline of 20.0% (1/5) plus the ~5–15pp lift the 3% blunder provides at Beginner/Intermediate, and remains inside the 10–40% band. A longer Expert run is a known follow-up.

9.2 Minimax upper bound (worst-case for the placer)

Purpose: establish the ceiling — if the Slider used full minimax (worst cell AND worst value with certainty at every chance node), could the placer still win? This is the hardest conceivable AI. The shipped expectimax's worst-available-value model (SR-4) sits between uniform-random and full minimax: it credits the player with every rack value currently off cooldown, but not with values still under cooldown. Not yet run — a full-minimax Slider is a possible future spike; the shipped tiers are validated by §9.1.

9.3 Placement strategy diversity (F6 check)

Purpose: verify that no single placement position or value is dominant. If the greedy placer always places in the same relative position or always spends the same value, the game has no decisions.

Method (position): log all placement positions across the simulation runs and compute the distribution. If a single position accounts for >50% of placements, flag for F6 concern and investigate guardrails. Measured: top-position frequency 11% at every tier — no dominant cell.

Method (value spending, supply-aware): the rack supply is deterministic, so randomness can no longer be relied on to force diverse value use — a dominant spending rhythm is a real risk. The cooldowns cap the 4+8 share of placements, giving value 2 a theoretical supply floor of 1 − 1/cd(4) − 1/cd(8) (steady state with every 4 and 8 spent the instant it recovers). The check: measured top-value frequency must stay under max(70% absolute, floor + 10pp) — the absolute line applies wherever supply allows it; the floor relaxation covers the Expert tier's intentionally lean rack, where the supply math makes 70% unattainable by design. Measured (final configs): Beginner top "2" = 62% (limit 70%) — PASS; Intermediate and Expert — see §9.1 table run data; both under their limits.

9.4 Human playtest simulation

Purpose: verify that a human player (not an optimal greedy placer) can realistically beat the Slider, and measure how long a win takes. The greedy placer is an upper bound; real humans play suboptimally.

Method: simulate a human-like placer that evaluates every (available rack value × empty cell) pair with the same depth-0 AI-response model as the greedy placer, then picks among the top-3 candidates with weights [0.6, 0.3, 0.1] — a decent human usually finds a good move, but not always the best one. Record: win rate and turns-to-win (avg / median / range).

TierAI depthBlunderRack {4, 8}PlacerRunsTarget win rateMeasured win rateTurns-to-win (avg / median / range)
Beginner0-ply5%2 / 4 (rich)Human-like (top-3 weighted)60>80%100% (60/60) — PASS72.7 / 72 / 33–124
Intermediate3-ply5%2 / 10 (mixed)Human-like (top-3 weighted)4040–70%50.0% (20/40) — PASS~217 / ~210 / 110–291
Expert4-ply5%4 / 12 (lean)Human-like (top-3 weighted)510–40%20.0% (1/5) — PASS225 / 225 / 225 (single win)

2026-10-14 re-measurement — auto-place defect removed. The figures above post-date the removal of a shipped defect: a spec'd "auto-place at one empty cell left" convenience that placed a tile on the player's behalf 160 ms after each AI slide. It functioned as a hidden rubber-band mechanic — auto-feeding the Slider merge saves at the endgame — and was silently costing the player wins (Beginner 81.7% → 100% after removal). All numbers in this table and in §9.1 were re-validated against the fixed build; the earlier pre-fix figures (Beginner 81.7%, Intermediate 55%, Expert 20%) are obsolete.

Beginner design goal — the joy of winning. Beginner is deliberately the weakest tier: 0-ply reactive play means the Slider never plans ahead, and the rich rack gives the player constant access to 4s and 8s. The 2025-10 tuning pass specifically targeted game length after the Saboteur lesson (a level requiring 32 consecutive correct picks is unplayable). Depth-0 halved Beginner's median win length from ~115 turns (at depth 1) to ~59 turns, with no win-rate cost — at shallow depth, the AI's base play is weak enough that blunder rate is a feel knob, not a difficulty knob. The result is a tier where a casual player wins in about a minute of active play, gets the dopamine hit, and is motivated to try Intermediate — which is where the real challenge ladder starts.

10. Internationalization

Stacked ships with client-side internationalization via the series' shared engine, public/shared/i18n.js, loaded as an external script immediately before the game's inline script, followed by the page dictionary public/shared/lang/stacked.js. The engine is offline-safe, dependency-free, and injects a fixed top-right language switcher into every page.

10.1 Supported languages and detection

10.2 Authoring pattern

10.3 Test harness independence

The headless test suite extracts only the game's first bare inline <script> block and evals it with a stubbed DOM; external <script src> tags are ignored, so window.RG_I18N is undefined in the harness. Consequently the boot is guarded with if (window.RG_I18N) RG_I18N.init('stacked'), and T() is defined to fall back to its English default (d != null ? d : k) whenever the engine is absent. This keeps the game fully playable offline and leaves all deterministic tests unaffected.