HomeMethod2048 spawn rule

How 2048 decides the next tile — and why four twos don't make eight

The game's reputation for cruelty comes from two decisions in one file: what value appears, and how far a merge is allowed to chain. Both were read from the original source at a pinned commit. The harness rebuilds the behaviour from the rule alone.

Independent guide. We read published source and rebuilt the rule in our own code. Not affiliated with the project's authors. Nothing here is a score-protection tool or a bot.

Findings

Read on 18 Oct 2026 from js/game_manager.js and js/grid.js at commit 478b6ec346e3787f589e4af751378d06ded4cbbc.

BehaviourWhat the source saysConfidenceWhat it does not prove
Next tile is a 2 nine times out of tenvar value = Math.random() < 0.9 ? 2 : 4; inside addRandomTileHigh — one line, no configDoes not apply to the two starting tiles, which are placed by a separate loop
Starting board has exactly 2 tilesthis.startTiles = 2; then a loop of that many callsHigh—
Position is uniform over empty cells onlycells[Math.floor(Math.random() * cells.length)] from availableCells()HighNo weighting toward centre or corners
A blocked swipe spawns nothingThe spawn call sits inside if (moved), after the tile loopHigh—
One merge per tile per moveGuard is tile.value === next.value && !next.mergedFromHighThat the same guard exists in every later fork
Score gain equals the resulting tileself.score += merged.value; where the merged value is the sumHigh—
Win flag at 2048, game continues after itif (merged.value === 2048) self.won = true; plus a keepPlaying flagHigh—
Over only when full and no adjacent paircellsAvailable || tileMatchesAvailable, scanning right and down neighboursHigh—
Merge order runs toward the swipeDirections are 0 up, 1 right, 2 down, 3 left; traversal is reversed for right and downHigh—
Board size comes from a data attribute, default 4size = parseInt(gridElement.dataset.size, 10) || 4;HighWhether any released build shipped a non-4 board
Best score is kept client-side onlyA StorageManager reads and writes local state; the game is restored from it on loadMediumNot confirmed by this run: the storage key names, and whether the saved state includes the score and the won flag. Open your own localStorage to check.

The counter-intuitive one. [2,2,2,2] swiped left gives [4,4], score +8 — not [8]. The merge guard marks a product as spent for this traversal. A chain that would double twice in one move does not exist.

The rule, in pseudocode

on swipe(dir):
  moved = false
  for cell in traversal(dir):
    if cell has tile t:
      n = first neighbour ahead of t
      if n is empty:
        slide t into n; moved = true
      else if n.value == t.value and n is not flagged merged:
        m = new tile(n.pos, t.value + n.value); m.merged = true
        replace n with m; t.clear()
        score += m.value
        if m.value == 2048: won = true
        moved = true
  if moved and any cell empty:
    v = (random() < 0.9) ? 2 : 4
    place v in a uniformly chosen empty cell
  if no empty cell and no adjacent equal pair: over = true
Two harnessesRule only

Is it really 90/10?

The simulation uses only the ternary. If the share of fours moves toward 10% as N grows, the line is what we claim.

10,000
press Run

The merge guard, live

Edit the row, then swipe left. With guard is the source's rule: a tile merges once. Without guard is the cascade people expect, where [2, 2, 2, 2] becomes 8.

press Swipe

Try it yourself

Inspect the 2048 repository I have checked out. Do not summarise the
game. Find the one place where a new tile's value is chosen, and quote
that line. Then tell me which behaviours are decided by that line
alone, and which ones I would have to read elsewhere. Name the file and
line for every claim, and say what you could not determine.

Pinning the commit matters. This repository's master is stable, but the Chrome dino repository used on the jump walkthrough has moved and its master path now returns 404. A repository name is not a citation. New to this? Set up REA first.

What we could not confirm. The spawn line uses the platform RNG, so the sequence is not reproducible without overriding Math.random — we did not verify whether any build seeds it. We also did not check the two starting tiles against a long sample, so "20% of games open with a 4 somewhere" is arithmetic, not measurement.

Next

Sources: Gabriele Cirulli, 2048, js/game_manager.js and js/grid.js, commit 478b6ec346e3787f589e4af751378d06ded4cbbc (commit dated 2024-10-24), retrieved 18 Oct 2026. Repository — check its LICENSE before republishing any excerpt. The rebuild and both harnesses are original to this page.