Tetris (NES)
Nintendo's 1989 Tetris for the NES, read through CelestialAmber's disassembly and measured in the running ROM.
On this page
Nintendo released Tetris for the NES in North America in November 19891. “Classic Tetris” usually means this version, and the Classic Tetris World Championship plays it on original consoles2.
The code read here is CelestialAmber’s TetrisNESDisasm, which builds the No-Intro Tetris (USA) ROM exactly3. Its labels, such as framesPerDropTable and DAS_DELAY, are the disassembly’s names, not Nintendo’s. Michael Birken’s “Applying Artificial Intelligence to Nintendo Tetris” is the code-level cross-check. Every timing below was also measured in the ROM itself, running headless in Mesen (probes/tetris/tetris-nes.lua).
#Dropping
Gravity is a table of frames per row, indexed by level: 48 frames per row at level 0, falling to 2 at level 19 and 1 at level 294,4.
.else
.byte $30,$2B,$26,$21,$1C,$17,$12,$0D
.byte $08,$06,$05,$05,$05,$04,$04,$04
.byte $03,$03,$03,$02,$02,$02,$02,$02
.byte $02,$02,$02,$02,$02,$01@lookupDropSpeed:
lda #$01
ldx levelNumber
cpx #$1D
bcs @noTableLookup
lda framesPerDropTable,xThe table stops at level 284. From level 29 the code skips it and drops the piece 1 frame per row5, so level 29 is twice as fast as level 285. Levels 20–28 can’t be picked on the menu and weren’t measured; every other level matched the table to the frame4.
A frame counter, fallTimer, drives the fall. When it reaches the level’s value the piece moves down a row; if that row is blocked, the piece locks where it is6. The game has no separate lock delay: a piece resting on the stack locks after one gravity interval6.
every frame with a piece in play: # playState_playerControlsActiveTetrimino
shift # shift_tetrimino, below
rotate if A or B was just pressed; undo if blocked
fallTimer += 1
if fallTimer >= FRAMES_PER_ROW[level], or a soft drop is due:
fallTimer = 0
row += 1
if blocked: row -= 1; lock
The first piece of each game hangs at the top for 96 frames7 before gravity starts. A pressed Down ends the wait7. Holding Down soft-drops the piece a row on the 3rd frame held, then every 2nd frame8, and each new piece needs a fresh press8. The game has no hard drop9.
#Moving
Delayed auto shift moves a held piece at once, then after 16 frames, then every 610,10. The counter is autorepeatX:
every frame with a piece in play: # shift_tetrimino
if Down held: stop
if Left or Right was just pressed:
count = 0; move
else if Left or Right held:
count += 1
if count >= 16: count = 10; move # DAS_RESET, DAS_DELAY
move: column += 1 or −1; if blocked: undo, count = 16
Three details of this loop shape how the game is played.
- A blocked shift charges DAS. It sets the count to 1611, so a piece held against a wall or the stack moves on the first frame the way is clear11.
- The charge outlives the piece. Spawning leaves the count alone, and the shift code doesn’t run between pieces. A piece that spawns with the direction still held and the count charged moves on frames 0, 6, 12, and 1812,12.
- Every new press resets the count and moves at once. Pressing on alternate frames moves a piece every 2 frames13, three times as often as DAS13.
Down and sideways movement exclude each other. Holding Down stops all shifting14, and a soft drop can’t start while Left or Right is held15. A rotation that would overlap the wall or the stack is undone, with no other position tried16.
#Level 29
At level 29 the drop outruns DAS. Before it locks on an empty board, a piece shifts 2 columns if held from spawn and 4 if DAS is already charged, in 19 frames of control17. Pieces spawn in the middle of the well, and most need 3 shifts to the right wall and 4 to the left (I needs 3 each way, O 4)18,18. A fresh hold reaches neither wall, but a charged one reaches both17.
Players call level 29 the “kill screen”, although the game continues past it19. Holding the D-pad can’t get pieces to the edges in time20. Birken names Thor Aackerlund as a player who overcame it by vibrating the D-pad21.
Competitive players call that faster pressing hypertapping. It spread after Joseph Saelee won the 2018 Classic Tetris World Championship with it22. In late 2020 Cheez worked out rolling, which presses faster still23. Both work because a new press always moves the piece at once13.
#Dealing pieces
The piece randomizer picks from a 16-bit linear feedback shift register (LFSR) that repeats after 32,767 steps25,25. The NMI handler steps it every frame, so the time a player takes over a piece changes the next one26.
on each spawn, fill the preview: # pickRandomTetrimino
picks += 1 # spawnCount; a new game doesn't reset it
i = (rng.high + picks) & 7
if i == 7 or PIECES[i] == previous: # PIECES: T J Z O S L I
step the generator
i = ((rng.high & 7) + id(previous)) mod 7 # id: the previous piece's orientation id
previous = PIECES[i]
The reroll guards against repeats but not completely, and it is biased27. It adds the previous piece’s orientation id, not its index, so one of its eight results is doubled. After an O or an S, the doubled result is the same piece again28.
Simulating the routine over every generator state gives the exact odds. A piece repeats the one before with probability 1/32 after a T, J, Z, L, or I and 1/16 after an O or S29. Over a long game 4.03%30 of pieces repeat, where a memoryless pick would repeat 1 in 7. The long-run shares run from 13.89% (L, I) to 14.68% (S)31. Birken’s figures for the shares differ slightly, because he averages the reroll over all seven pieces equally29.
The running game agrees. In six games of 800 pieces each, 4.46% of pieces repeated the one before32,32. Select shows or hides the preview33.
#Delays
The entry delay between a lock and the next spawn is 10 to 18 frames34, longer the higher the piece locks34. The delay is the screen redraw. The game copies the well to the screen 4 rows a frame. A lock waits for the copy from 2 rows above the piece to the floor; the row check then restarts the copy at the top, and the next piece waits for the whole well34.
A line clear adds 17 to 20 frames35. The animation blanks two columns of each cleared row every 4th frame, in 5 steps, and its first step waits for the global frame counter35. The number of lines cleared doesn’t change it.
#Scoring and levels
A clear of 1, 2, 3, or 4 lines scores 40, 100, 300, and 1,200 × (level + 1)36,36. The clear that raises the level scores at the new level37. The score stops at 999,99938,38.
Holding A while pressing Start on the level menu adds 10 to the start level39. From start levels 0 to 9 the first level-up comes after 10 lines per level, at 10 × (start + 1) lines40. From the higher start levels it comes sooner, at 100 lines from start levels 10 to 15, and 110, 120, 130, and 140 from 16 to 1940. The code compares the binary level with the decimal line count41. Whenever the lines’ ones digit turns 0, the level rises if it is below the hundreds and tens digits read as one hexadecimal byte41. After the first transition the level rises every 10 lines40.
#The PAL version
The European build, from the same source with PAL = 1, shortens DAS to 12 frames, then every 442,42. Its gravity table runs from 36 frames per row at level 0 to 1 at level 1943,43. The research set has no PAL ROM, so neither was measured.
#How it was measured
The probe boots the ROM in Mesen and reaches every game through the menus with scripted input. It reads the game’s state from RAM by the disassembly’s labels. It writes RAM in only three ways: a level beyond the menu’s range, filled rows so that lines clear on demand, and an emptied board so that a randomizer run never ends. None of those writes touches the timers, the input handling, or the generator. node probes/tetris/tetris-nes.mjs re-runs all of it in about two minutes and checks each result against its claim.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Delayed auto shift | Delay, then repeat | 16 frames, then every 6; charge survives walls and spawns |
| Piece randomizer | Reroll | one reroll against repeats, biased by the previous piece |
| Entry delay | Screen redraw | set by the time to redraw the well |
| Drop speed | Level table | a table of frames per row by level |
| Clearing | Full row | a row of 10 filled cells clears, and the rows above move down |
| Demo playback | Recorded input | 256 (buttons, frames − 1) pairs and a fixed 256-byte piece list; a recorder for the format is left in the code, switched off |
| Lock delay | None | a piece that can't fall locks at its next gravity step |
| Chain | None | rows move down whole, so one clear can't set off another |
Every claim about this game, by concept (50)
References
- ^Nintendo released Tetris for the NES in North America in November 1989.WikiTetris Wiki, “Tetris (NES, Nintendo)”
How we know
Tetris for Nintendo Entertainment System was released in November, 1989 in North America and published by Nintendo.
lead · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^"Classic Tetris" usually means this NES version, and the Classic Tetris World Championship plays it on original consoles.MagazineTrew 2022
How we know
"Classic Tetris" usually refers to the NES port of the game. It's considered the gold standard original and is the version played in the CTWC tournaments. … This means original NES consoles, controllers and big old CRT TVs.
section on CTWC · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^The disassembly builds the No-Intro Tetris (USA) ROM exactly; with the iNES header
tetris.asmwrites in place of the ROM's NES 2.0 header, the file's SHA-1 is the one intetris.sha1.VerifiedCelestialAmber/TetrisNESDisasm · “Tetris (USA)”How we know
177747840541bfc62a28a5957692a98c550bd6b2b tetris.nestetris.sha1 line 1 at 94581c0 · upstream ↗ 14.byte 'N', 'E', 'S', $1A ; ID 15.byte $02 ; 16k PRG chunk count 16.byte $02 ; 8k CHR chunk count 17.byte INES_MIRROR | (INES_SRAM << 1) | ((INES_MAPPER & $f) << 4)
tetris.asm lines 14–19 at 94581c0 · upstream ↗ In the cartridge (“Tetris (USA)”): the NES 2.0 header the probe replaces. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Tetris (USA) (SHA-1
3026d28b63d9…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdefGravity comes from
framesPerDropTable; a piece falls one row every 48 frames at level 0, never more slowly at a higher level, holding steady across levels 10–12, 13–15, and 16–18, down to 2 frames at levels 19–28, and 1 frame from level 29 on.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris" · “Tetris (USA)” · Tetris Wiki, “Tetris (NES, Nintendo)”revisedHow we know
1607.else 1608 .byte $30,$2B,$26,$21,$1C,$17,$12,$0D 1609 .byte $08,$06,$05,$05,$05,$04,$04,$04 1610 .byte $03,$03,$03,$02,$02,$02,$02,$02 1611 .byte $02,$02,$02,$02,$02,$01
main.asm lines 1607–1611 at 94581c0 · upstream ↗ 1584@lookupDropSpeed: 1585 lda #$01 1586 ldx levelNumber 1587 cpx #$1D 1588 bcs @noTableLookup 1589 lda framesPerDropTable,x
main.asm lines 1584–1595 at 94581c0 · upstream ↗ The table only contains 30 entries. Above level 29, the frames per drop is locked at 1.
Dropping Tetriminos · archived copy ↗ In the cartridge (“Tetris (USA)”): framesPerDropTable, CPU $898E. We don't reproduce the bytes.
The following table of gravity speeds was observed and later found to be stored at $898E (offset $099E in the iNES format ROM)
Details · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Tetris (USA) (SHA-1
3026d28b63d9…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Revised after a check by a second AI model, 2026-10-21: Gravity holds steady across levels 10–12, 13–15, and 16–18.
- ^ abFrom level 29 (
$1D) on, the game skips the table and drops the piece a row every frame.VerifiedCelestialAmber/TetrisNESDisasmHow we know
1585 lda #$01 1586 ldx levelNumber 1587 cpx #$1D 1588 bcs @noTableLookup ⋮ 1590@noTableLookup: 1591 sta dropSpeed
main.asm lines 1584–1591 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ ab
fallTimercounts frames, and when it reaches the level's value the piece moves down a row; if that row is blocked, the piece locks where it is, so a resting piece locks after one gravity interval.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
1441gameModeState_updateCountersAndNonPlayerState: ⋮ 1448 inc player1_fallTimer
main.asm lines 1441–1449 at 94581c0 · upstream ↗ 1570@drop: lda #$00 1571 sta fallTimer 1572 lda tetriminoY 1573 sta originalY 1574 inc tetriminoY 1575 jsr isPositionValid 1576 beq @ret 1577 lda originalY 1578 sta tetriminoY 1579 lda #$02 1580 sta playState ⋮ 1592 lda fallTimer ⋮
main.asm lines 1570–1594 at 94581c0 · upstream ↗ This means that the lock delay—the maximum number of frames that a Tetrimino waits while supported before locking—is equal to the drop delay.
Dropping Tetriminos · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abThe first piece of a game hangs at the top for 96 frames before gravity starts, because
autorepeatYstarts at$A0(−96) and gravity waits until it counts up to 0; pressing Down ends the wait.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
94INITIAL_AUTOREPEAT_Y := $A0constants.asm line 94 at 94581c0 · upstream ↗ 1239 lda #INITIAL_AUTOREPEAT_Y 1240 sta player1_autorepeatY
main.asm lines 1239–1240 at 94581c0 · upstream ↗ 1530drop_tetrimino: 1531 lda autorepeatY 1532 bpl @notBeginningOfGame 1533 lda newlyPressedButtons 1534 and #BUTTON_DOWN 1535 beq @incrementAutorepeatY
main.asm lines 1530–1537 at 94581c0 · upstream ↗ The first spawned piece has an opening entry delay of 96 frames. A soft drop will cancel it, but shifting and rotating won’t.
Gamepad Version · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abHolding Down drops the piece a row on its 3rd frame and then every 2nd frame, and each piece needs a fresh press, because spawning zeroes
autorepeatYand only a new press starts the count.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
1544 lda newlyPressedButtons 1545 and #BUTTON_DPAD 1546 cmp #BUTTON_DOWN 1547 bne @lookupDropSpeed 1548 lda #$01 1549 sta autorepeatY ⋮ 1554 and #BUTTON_DPAD 1555 cmp #BUTTON_DOWN ⋮ 1558 sta autorepeatY ⋮ 1562@downPressed: 1563 inc autorepeatY 1564 lda autorepeatY ⋮
main.asm lines 1544–1569 at 94581c0 · upstream ↗ Holding Down triggers a soft drop every other frame after an initial delay of 3 frames.
Gamepad Version · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^The game has no hard drop; the only fast drop is the soft drop on Down.WebBirken, "Applying AI to Nintendo Tetris" · Tetris Wiki, “Tetris (NES, Nintendo)”
How we know
Nintendo Tetris does not support hard drops.
Dropping Tetriminos · archived copy ↗ Lock delay, wall kick, and hard drop are not present.
Details · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^ abHolding Left or Right moves the piece at once, again 16 frames later, and then every 6 frames; the press zeroes
autorepeatX, each held frame adds 1, and atDAS_RESET(16) the piece moves and the count drops toDAS_DELAY(10).VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris" · “Tetris (USA)”How we know
89DAS_DELAY := $0A 90DAS_RESET := $10
constants.asm lines 89–90 at 94581c0 · upstream ↗ 1622 lda newlyPressedButtons 1623 and #BUTTON_LEFT+BUTTON_RIGHT 1624 bne @resetAutorepeatX 1625 lda heldButtons 1626 and #BUTTON_LEFT+BUTTON_RIGHT 1627 beq @ret 1628 inc autorepeatX 1629 lda autorepeatX 1630 cmp #DAS_RESET 1631 bmi @ret 1632 lda #DAS_DELAY 1633 sta autorepeatX ⋮
main.asm lines 1622–1638 at 94581c0 · upstream ↗ holding down one of those direction buttons causes the game to automatically shift the piece every 6 frames after an initial delay of 16 frames.
Shifting Tetriminos · archived copy ↗ In the cartridge (“Tetris (USA)”): shift_tetrimino, CPU $89AE. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Tetris (USA) (SHA-1
3026d28b63d9…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abA blocked shift sets
autorepeatXto 16, so a piece held against a wall or the stack keeps DAS charged and moves on the first frame the way is clear.VerifiedCelestialAmber/TetrisNESDisasmHow we know
1661@restoreX: 1662 lda originalY 1663 sta tetriminoX 1664 lda #DAS_RESET 1665 sta autorepeatX
main.asm lines 1661–1665 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abSpawning a piece leaves
autorepeatXalone, so a charge carries over; with the direction held through the entry delay, the new piece moves on its first frame and every 6 frames after.VerifiedCelestialAmber/TetrisNESDisasm · Tetris Wiki, “Tetris (NES, Nintendo)”How we know
2920@spawnPiece: 2921 lda #$00 2922 sta twoPlayerPieceDelayCounter 2923 sta fallTimer 2924 sta tetriminoY 2925 lda #$01 2926 sta playState 2927 lda #$05 2928 sta tetriminoX ⋮ 2943@resetDownHold: 2944 lda #$00 2945 sta autorepeatY
main.asm lines 2920–2945 at 94581c0 · upstream ↗ 489playState_playerControlsActiveTetrimino: 490 jsr shift_tetrimino
main.asm lines 489–492 at 94581c0 · upstream ↗ This means that any DAS charge left over from the previous piece can be redirected during ARE.
Details · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcEvery new press of Left or Right zeroes the DAS count and moves the piece at once, so pressing on every other frame moves it every 2 frames.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"
How we know
1622 lda newlyPressedButtons 1623 and #BUTTON_LEFT+BUTTON_RIGHT 1624 bne @resetAutorepeatX
main.asm lines 1622–1624 at 94581c0 · upstream ↗ as long as the horizontal direction button is released exactly every other frame, it is possible to shift the Tetrimino at half the rate that it drops on levels 29 and above.
Dropping Tetriminos · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^While Down is held the piece can't shift;
shift_tetriminoreturns before reading Left or Right.VerifiedCelestialAmber/TetrisNESDisasmHow we know
1616shift_tetrimino: 1617 lda tetriminoX 1618 sta originalY 1619 lda heldButtons 1620 and #BUTTON_DOWN 1621 bne @ret
main.asm lines 1616–1621 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^A soft drop can't start while Left or Right is held.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"
How we know
1540@playing: 1541 lda heldButtons 1542 and #BUTTON_LEFT+BUTTON_RIGHT 1543 bne @lookupDropSpeed
main.asm lines 1540–1543 at 94581c0 · upstream ↗ When Left or Right is pressed, it is not possible to soft drop.
Gamepad Version · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^A rotation that would overlap a wall or the stack is undone; the game tries no other position.CodeCelestialAmber/TetrisNESDisasm
How we know
1476 inx 1477 lda rotationTable,x 1478 sta currentPiece 1479 jsr isPositionValid 1480 bne @restoreOrientationID ⋮ 1490 lda rotationTable,x 1491 sta currentPiece 1492 jsr isPositionValid 1493 bne @restoreOrientationID ⋮ 1498@restoreOrientationID: 1499 lda originalY 1500 sta currentPiece
main.asm lines 1476–1501 at 94581c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abAt level 29 on an empty board, a piece is under control for 19 frames; held from spawn it shifts 2 columns, with DAS charged 4, and tapped it shifts once every 2 frames.VerifiedCelestialAmber/TetrisNESDisasm
How we know
1585 lda #$01 1586 ldx levelNumber 1587 cpx #$1D 1588 bcs @noTableLookup
main.asm lines 1584–1591 at 94581c0 · upstream ↗ 1628 inc autorepeatX 1629 lda autorepeatX 1630 cmp #DAS_RESET 1631 bmi @ret 1632 lda #DAS_DELAY 1633 sta autorepeatX ⋮ 1638 sta autorepeatX ⋮ 1665 sta autorepeatX
main.asm lines 1622–1665 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abPieces spawn centered on column 5 of 0–9; in spawn orientation T, J, Z, S, and L cover columns 4–6, O 4–5, and I 3–6, so most pieces need 3 shifts to reach the right wall and 4 to reach the left.CodeCelestialAmber/TetrisNESDisasm
How we know
2927 lda #$05 2928 sta tetriminoX
main.asm lines 2927–2928 at 94581c0 · upstream ↗ 1760 ; y offset, tile ID, x offset per mino per orientation ⋮ 1763 .byte 0, tile1,-1, 0, tile1, 0, 0, tile1, 1, 1, tile1, 0 ; $02 t down (spawn) ⋮ 1774 .byte 0, tile1,-1, 0, tile1, 0, 1, tile1,-1, 1, tile1, 0 ; $0A o (spawn) ⋮ 1785 .byte 0, tile1,-2, 0, tile1,-1, 0, tile1, 0, 0, tile1, 1 ; $12 i horizontal (spawn)
main.asm lines 1760–1785 at 94581c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^Players call level 29 the "kill screen", although the game goes on.WebBirken, "Applying AI to Nintendo Tetris" · Trew 2022
How we know
most players cannot endure the drop speed of level 29, which swiftly brings the game to an end. For this reason, it has become associated with the notation of a kill screen.
The Kill Screen · archived copy ↗ beating level 29 (aka the "kill screen")
section on the maxout · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Engadget describes the level 29 kill screen as a wall for players who hold the D-pad, because DAS can't carry pieces to either edge in time.MagazineTrew 2022 · Birken, "Applying AI to Nintendo Tetris"
How we know
DAS simply cannot move the pieces to either edge fast enough, meaning that once the "stack" is above a certain height math takes over and failure is guaranteed.
section on the kill screen · archived copy ↗ At that drop speed, the DAS does not permit the piece to reach the edges of the playfield before lock, quickly ending the game for most humans.
Dropping Tetriminos · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Birken names Thor Aackerlund as a player who beat DAS at level 29 by vibrating the D-pad.WebBirken, "Applying AI to Nintendo Tetris"
How we know
However, some players, most notably Thor Aackerlund, overcome the DAS by rapidly vibrating the D-pad.
Dropping Tetriminos · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Hypertapping is moving pieces with many quick presses of the D-pad instead of holding it; it spread in competition after a hypertapping player won the 2018 Classic Tetris World Championship.MagazineZwiezen 2021 · Trew 2022
How we know
But another way to play is called “hypertapping.” This involves hitting the d-pad with lots of quick presses, resulting in faster movement. … It wasn’t until 2018, after a young player won a prestigious competition using hypertapping, that more players starting using it.
paragraph 4 · archived copy ↗ He used a style called "hypertapping" – a contorted mix of fingers and thumbs designed to sidestep the game's built-in speed limit – and it allows you to move pieces much faster than DAS.
section on Neubauer and Saelee · archived copy ↗ Saelee's victory at the 2018 CTWC finals may have surprised everyone
section on Saelee · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Rolling, which the player Cheez worked out in late 2020, keeps light pressure on the D-pad while the fingers roll across the back of the controller, and moves pieces faster than hypertapping.MagazineZwiezen 2021 · Trew 2022
How we know
Eventually, in November 2020, Cheez_Fish figured out that they could roll their fingers on the back of the controller while pressing the d-pad buttons in the desired direction using a slight amount of pressure.
paragraph 6 · archived copy ↗ you can move pieces left and right even faster than with hypertapping.
section on rolling · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Birken reports that the game itself breaks down around 1,550 lines, usually freezing, sometimes resetting or going black, because the scoring loop runs once per level and takes longer than a frame at high levels.WebBirken, "Applying AI to Nintendo Tetris"revised
How we know
The actual kill screen occurs around 1550 lines. It manifests itself in different ways. Sometimes the game resets. Other times, the screen just goes black. Usually, the game freezes just after clearing a line … For high levels, the large number of iterations affects the timing of the game as each frame takes longer than 1/60th of a second to generate.
The Kill Screen · archived copy ↗ The quote matches our archived copy.
Revised after a check by a second AI model, 2026-10-21.
- ^ abThe random number generator is a 16-bit linear feedback shift register at
$0017; each step shifts it right and feeds bit 1 XOR bit 9 into the top bit, and from its seed,$8988, it repeats after 32,767 steps.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris" · “Tetris (USA)”How we know
5468generateNextPseudorandomNumber: 5469 lda tmp1,x 5470 and #$02 5471 sta tmp1 5472 lda tmp2,x 5473 and #$02 5474 eor tmp1
main.asm lines 5468–5483 at 94581c0 · upstream ↗ 347@continueWarmBootInit: 348 ldx #$89 349 stx rng_seed 350 dex 351 stx rng_seed+1
main.asm lines 347–351 at 94581c0 · upstream ↗ This PRNG repeatedly and deterministically generates 32,767 distinct values, each cycle starting with the original seed.
Picking Tetriminos · archived copy ↗ In the cartridge (“Tetris (USA)”): generateNextPseudorandomNumber, CPU $AB47. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Tetris (USA) (SHA-1
3026d28b63d9…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abThe NMI handler steps the generator every frame, so the time a player takes to place a piece changes which piece comes next.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"
How we know
270.if NWC <> 1 271 ldx #rng_seed 272 ldy #$02 273 jsr generateNextPseudorandomNumber 274.endif
main.asm lines 270–274 at 94581c0 · upstream ↗ Meaning, the number of frames that it takes the player to position a piece actually affects which piece comes up next.
Picking Tetriminos · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^
pickRandomTetriminoadds a pick counter to the generator's high byte and keeps the low 3 bits; a result of 7, or the same piece as last time, makes it step the generator and take the high byte's low 3 bits plus the previous piece's orientation id, modulo 7, with no further check.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
2974 inc spawnCount 2975 lda rng_seed 2976 clc 2977 adc spawnCount 2978 and #$07 2979 cmp #$07 2980 beq @invalidIndex 2981 tax 2982 lda spawnTable,x 2983 cmp spawnID 2984 bne useNewSpawnID 2985@invalidIndex: ⋮
main.asm lines 2974–3002 at 94581c0 · upstream ↗ 3013spawnTable: 3014 .byte tDown, jDown, zHoriz, oFixed, sHoriz, lDown, iHoriz
main.asm lines 3013–3014 at 94581c0 · upstream ↗ Otherwise, the next pseudorandom number is generated and a mask is applied to retain the lower 3 bits of the high byte before adding the prior spawn orientation ID.
Picking Tetriminos · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^The reroll adds the previous piece's orientation id, not its index, so one of its eight results is doubled; after an O (
$0A) or an S ($0B) the doubled result is the same piece again.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
123tDown = $02 ⋮ 128jDown = $07 129zHoriz = $08 ⋮ 131oFixed = $0A 132sHoriz = $0B ⋮ 135lDown = $0E ⋮ 139iHoriz = $12
constants.asm lines 121–139 at 94581c0 · upstream ↗ Using the prior spawn orientation ID in the sum as opposed to the prior Tetrimino type introduces a bias because the spawn orientation ID values are not evenly distributed.
Picking Tetriminos · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abRun over every state of the generator and every pick count, the routine repeats a T, J, Z, L, or I with probability 1/32 and an O or S with 1/16, so 4.0% of the pieces in a long game repeat the one before.VerifiedCelestialAmber/TetrisNESDisasm
How we know
2974 inc spawnCount 2975 lda rng_seed 2976 clc 2977 adc spawnCount 2978 and #$07 2979 cmp #$07 2980 beq @invalidIndex 2981 tax 2982 lda spawnTable,x 2983 cmp spawnID 2984 bne useNewSpawnID 2985@invalidIndex: ⋮
main.asm lines 2974–3002 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^Over a long game, 4.03% of pieces repeat the one before, against 14.3% (1 in 7) for a uniform, memoryless pick.VerifiedCelestialAmber/TetrisNESDisasm
How we know
2974 inc spawnCount 2975 lda rng_seed 2976 clc 2977 adc spawnCount 2978 and #$07 2979 cmp #$07 2980 beq @invalidIndex 2981 tax 2982 lda spawnTable,x 2983 cmp spawnID 2984 bne useNewSpawnID 2985@invalidIndex: ⋮
main.asm lines 2974–3002 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^In a long game the routine deals T and S most often (14.67% and 14.68%) and L and I least (13.89% each); J, Z, and O come 14.29–14.30% of the time.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"
How we know
2974 inc spawnCount 2975 lda rng_seed 2976 clc 2977 adc spawnCount 2978 and #$07 2979 cmp #$07 2980 beq @invalidIndex 2981 tax 2982 lda spawnTable,x 2983 cmp spawnID 2984 bne useNewSpawnID 2985@invalidIndex: ⋮
main.asm lines 2974–3002 at 94581c0 · upstream ↗ T and S appear more frequently and L and I less frequently.
Picking Tetriminos · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abIn 4,800 pieces dealt by the running game, 4.46% repeated the piece before, against 4.03% simulated and 14.3% for a uniform pick; 6.29% of O and S pieces repeated (simulated 6.25%) and 3.76% of the others (3.13%).Verified“Tetris (USA)” · CelestialAmber/TetrisNESDisasm
How we know
In the cartridge (“Tetris (USA)”): pickRandomTetrimino, CPU $9907; generateNextPseudorandomNumber, CPU $AB47. We don't reproduce the bytes.
2974 inc spawnCount 2975 lda rng_seed 2976 clc 2977 adc spawnCount 2978 and #$07 2979 cmp #$07 2980 beq @invalidIndex 2981 tax 2982 lda spawnTable,x 2983 cmp spawnID 2984 bne useNewSpawnID 2985@invalidIndex: ⋮
main.asm lines 2974–3002 at 94581c0 · upstream ↗ Measured by a script. It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^Select shows or hides the next piece.CodeCelestialAmber/TetrisNESDisasm
How we know
1454 lda newlyPressedButtons_player1 1455 and #BUTTON_SELECT 1456 beq @ret 1457 lda displayNextPiece ⋮ 1459 eor #$01 1460 sta displayNextPiece
main.asm lines 1453–1460 at 94581c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcThe next piece spawns 10 frames after a lock with the piece's center on row 18 or 19, and 2 frames later for every 4 rows higher, up to 18 frames.VerifiedCelestialAmber/TetrisNESDisasm · Tetris Wiki, “Tetris (NES, Nintendo)”
How we know
2484@playStateNotDisplayLineClearingAnimation: 2485 lda player1_vramRow 2486 sta vramRow 2487 lda #>playfield 2488 sta playfieldAddr+1 2489 jsr copyPlayfieldRowToVRAM 2490 jsr copyPlayfieldRowToVRAM 2491 jsr copyPlayfieldRowToVRAM 2492 jsr copyPlayfieldRowToVRAM
main.asm lines 2484–2492 at 94581c0 · upstream ↗ 3532updatePlayfield: 3533 ldx tetriminoY 3534 dex 3535 dex ⋮ 3542 sta vramRow
main.asm lines 3532–3542 at 94581c0 · upstream ↗ 3074@notGameOver: 3075 lda vramRow 3076 cmp #$20 3077 bmi @ret
main.asm lines 3074–3077 at 94581c0 · upstream ↗ 3263 lda #$00 3264 sta vramRow
main.asm lines 3263–3264 at 94581c0 · upstream ↗ 2896playState_spawnNextTetrimino: 2897 lda vramRow 2898 cmp #$20 2899 bmi @ret
main.asm lines 2896–2899 at 94581c0 · upstream ↗ pieces that lock in the bottom two rows are followed by 10 frames of entry delay, and each group of 4 rows above that has an entry delay 2 frames longer than the last.
Details · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abA line clear adds 17 to 20 frames to the entry delay, for the animation that blanks two columns of each cleared row every 4th frame, in 5 steps.VerifiedCelestialAmber/TetrisNESDisasm · Tetris Wiki, “Tetris (NES, Nintendo)”
How we know
2757updateLineClearingAnimation: 2758 lda frameCounter 2759 and #$03 2760 bne @ret
main.asm lines 2757–2760 at 94581c0 · upstream ↗ 2821 inc rowY 2822 lda rowY 2823 cmp #$05 2824 bmi @ret 2825 inc playState
main.asm lines 2821–2825 at 94581c0 · upstream ↗ line clear delay is an additional 17~20 frames depending on the frame that the piece locks; the animation has 5 steps that advance when the global frame counter modulo 4 equals 0.
Details · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abClearing 1, 2, 3, or 4 lines at once scores 40, 100, 300, or 1,200 points times one more than the level.VerifiedCelestialAmber/TetrisNESDisasm
How we know
3529pointsTable: 3530 .word $0000,$0040,$0100,$0300 3531 .word $1200
main.asm lines 3529–3531 at 94581c0 · upstream ↗ 3460addLineClearPoints: 3461 lda #$00 3462 sta holdDownPoints 3463 lda levelNumber 3464 sta generalCounter 3465 inc generalCounter 3466L9C37: lda completedLines 3467 asl a 3468 tax 3469 lda pointsTable,x
main.asm lines 3460–3469 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^The clear that raises the level scores at the new level, because the lines and the level go up before the points are added.VerifiedCelestialAmber/TetrisNESDisasm
How we know
3422@incrementLevel: 3423 inc levelNumber ⋮ 3429L9BFB: dex 3430 bne incrementLines
main.asm lines 3422–3430 at 94581c0 · upstream ↗ 3460addLineClearPoints: ⋮ 3463 lda levelNumber
main.asm lines 3460–3465 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abThe score stops at 999,999; when its top digit would pass 9, the code writes 99 99 99.VerifiedCelestialAmber/TetrisNESDisasm
How we know
3508L9C84: lda score+2 3509 and #$F0 3510 cmp #$A0 3511 bcc L9C94 3512 lda #$99 3513 sta score 3514 sta score+1 3515 sta score+2
main.asm lines 3508–3515 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^Holding A while pressing Start on the level menu adds 10 to the chosen level, so games can start at levels 10–19.VerifiedCelestialAmber/TetrisNESDisasm
How we know
867 lda newlyPressedButtons_player1 868 cmp #BUTTON_START 869 bne @checkBPressed 870 lda heldButtons_player1 871 cmp #BUTTON_A+BUTTON_START 872 bne @startAndANotPressed 873 lda player1_startLevel 874 clc 875 adc #$0A
main.asm lines 867–876 at 94581c0 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcThe level first rises at 10 × (start level + 1) lines from start levels 0–9, at 100 lines from 10–15, and at 110, 120, 130, and 140 lines from 16, 17, 18, and 19; after that it rises every 10 lines.VerifiedCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"
How we know
3395L9BC7: lda lines 3396 and #$0F ⋮ 3406L9BD0: lda lines+1 3407 sta generalCounter2 3408 lda lines 3409 sta generalCounter 3410 lsr generalCounter2 3411 ror generalCounter 3412 lsr generalCounter2 3413 ror generalCounter 3414 lsr generalCounter2 3415 ror generalCounter ⋮
main.asm lines 3395–3423 at 94581c0 · upstream ↗ Consequentially, if the player decided to start at level 17, the level would actually advance at 120 lines because 18 exceeds 17.
Lines and Statistics · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abEach time the lines' ones digit turns 0, the level goes up by 1 if it is below the hundreds and tens digits read as one hexadecimal byte; 130 lines gives
$13, which is 19.CodeCelestialAmber/TetrisNESDisasm · Birken, "Applying AI to Nintendo Tetris"How we know
3406L9BD0: lda lines+1 3407 sta generalCounter2 3408 lda lines 3409 sta generalCounter 3410 lsr generalCounter2 3411 ror generalCounter 3412 lsr generalCounter2 3413 ror generalCounter 3414 lsr generalCounter2 3415 ror generalCounter 3416 lsr generalCounter2 3417 ror generalCounter ⋮
main.asm lines 3406–3420 at 94581c0 · upstream ↗ However, at $9BEA the level number is directly compared against the packed BCD value in $00A8. A table lookup to convert the BCD value to decimal is missing, an apparent bug.
Lines and Statistics · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abThe PAL build's DAS waits 12 frames and then repeats every 4.CodeCelestialAmber/TetrisNESDisasm
How we know
72.if PAL = 1 ⋮ 74DAS_DELAY := $08 75DAS_RESET := $0C
constants.asm lines 72–75 at 94581c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abThe PAL build's gravity table starts at 36 frames per row at level 0 and reaches 1 frame at level 19.CodeCelestialAmber/TetrisNESDisasm
How we know
1601framesPerDropTable: 1602.if PAL = 1 1603 .byte $24,$20,$1D,$19,$16,$12,$0F,$0B 1604 .byte $07,$05,$04,$04,$04,$03,$03,$03 1605 .byte $02,$02,$02,$01,$01,$01,$01,$01 1606 .byte $01,$01,$01,$01,$01,$01
main.asm lines 1601–1606 at 94581c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
Sources
Code
- (CelestialAmber), Amber Brault and contributors. 2024. “TetrisNESDisasm: a disassembly of Tetris (NES).” Commit 94581c0. CelestialAmber/TetrisNESDisasm @ 94581c0 · licence, all uses
- 1989. “Tetris (USA).” · licence, all uses
Secondary
- Tetris Wiki contributors. 2024. “Tetris (NES, Nintendo).” Tetris Wiki. original · archived · licence, all uses
- Trew, James. 2022. “How Gen Z is pushing NES Tetris to its limits.” Engadget. original · archived · licence, all uses
- Birken, Michael. 2014. “Applying Artificial Intelligence to Nintendo Tetris.” original · archived · licence, all uses
- Zwiezen, Zack. 2021. “NES Tetris Players Call It 'Rolling,' And They're Setting New World Records.” Kotaku. original · archived · licence, all uses