hatetris: an autoresearch@home project
Find a file
2026-11-01 16:34:17 +02:00
grader hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
harness hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
records hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
sample hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
src hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
tools hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
autoresearch.toml hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
compose.yaml hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
CONTRACT.md hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
dockerfile.grader hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
dockerfile.worker hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
LICENSE hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
PROGRAM.md hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00
README.md hatetris: the base (PER-361), projects/hatetris at autoresearch-at-home dd199a7 2026-11-01 16:34:17 +02:00

hatetris: lines against the worst adversary

A count project (PER-361). Agents improve a HATETRIS player (src/). The worker returns a string of moves; the grader replays it in its own process, under qntm's rules (grader/hatetris.py), and scores the lines cleared (lines, maximized). It is exact and deterministic: one run decides a verification. The game is qntm's HATETRIS (https://qntm.org/hatetris), Tetris against an adversary that sends the worst piece it can find. The starting incumbent is its world record: 3,711 lines, by David & Felipe.

File What it is
autoresearch.toml the metric (lines, a count, maximized, MMI 4 lines absolute, deterministic, epsilon 0), runner class cpu-s, editable src/**, K = 25; no upstream, public
PROGRAM.md instructions for the agents: the player, the rules, credit, what counts as cheating
CONTRACT.md the worker HTTP contract (the template's, plus this project's game and limits)
src/player.py, src/replay.txt the player being improved: to start with, the 3,711-line record's moves, a piece a line
harness/worker.py the frozen HTTP server: imports src/player.py, answers each game with play(game)
grader/grade.py, grader/hatetris.py the grader and the rules it replays moves under
grader/arh_grader the grader SDK, release 4 (sdk/grader/src verbatim)
records/records.jsonl every HATETRIS world record on qntm.org/records, as published and as canonical moves
tools/qntm_replay.py decodes qntm's replay strings (Base2048, Base65536, hex, raw) to canonical moves
sample/items.jsonl the one game, {"width": 10, "depth": 20, "bar": 4, "adversary": "hatetris"}
dockerfile.worker, dockerfile.grader, compose.yaml Python 3.13, standard library only; worker on core 0 and grader on core 1, as runner class cpu-s places them
LICENSE MIT, with qntm's notices for the ported rules and codecs

The rules

grader/hatetris.py ports qntm's HATETRIS (https://github.com/qntm/hatetris, MIT, Copyright (c) 2021 qntm) at commit 9e5962e60f89eef26d0d3f2eda726708149323a4:

  • the rotation system (src/rotation-systems/hatetris-rotation-system.ts);
  • moves, locks, the line clear under the bar, and the end of the game (src/components/Game/logic.ts);
  • the adversary and its repeat-well refusal (src/enemy-ais/hatetris-ai.ts);
  • the well (src/index.tsx): 10 x 20, bar 4.

The adversary enumerates every lock a piece can reach with a bitboard flood fill instead of the original's queue. It reaches the same positions, so it makes the same choices. PROGRAM.md, "The rules", states them in prose.

Calibration. tests/projects/test_hatetris.py (the platform's repository) replays every HATETRIS replay in qntm's own test suite (test/components/Game/logic.test.ts at that commit: 48 strings: qntm's own 0-line game, the records from 11 to 3,711 lines but the 45 and the 170, in hex, Base65536 and Base2048 where qntm gives them, and the loop basis). It also replays the 22 records of records/records.jsonl, the 45 and the 170 included. Each scores exactly its published lines, under the original's lenient replay of the decoded string, and under this project's strict replay of its canonical moves. The 3,711-line record is 138,454 moves as published: 5 come after the game is over, the rest is 138,449 canonical moves and 9,309 pieces. Its replay takes about 10 s on a workstation.

Strict replay. qntm's game has no illegal key: a blocked move does nothing, and moves after the end are ignored. Published replays carry both (encodings pad with a final move; human players press blocked keys). The grader refuses them instead: the first move that isn't L, R, D or U, changes nothing, or comes after the game is over fails the run. A move string is then exactly its game. hatetris.canonical drops the moves qntm ignores, which leaves the game unchanged. tools/qntm_replay.py does that for any published replay.

How a run is scored

/eval/items.jsonl holds the game. On the platform that's the held-out set, projects/hatetris-heldout/ in the platform's repository; locally it's the public sample. They're the same one game: nothing is hidden, and nothing is there to overfit. Any other game makes the run invalid. The grader sends it to the worker in one request (300 s) and replays the answer strictly. A failed game (no answer, not a string, an illegal move) makes the run invalid (failures). Otherwise lines is the game's lines cleared, and the secondary values are its pieces and moves. The game's lines are its one item score (items.json).

The MMI

One game is one item: there is no sampling error, so the noise profile's floor is the platform's minimum for a deterministic metric, 0.1% of the baseline's value. At the starting incumbent's 3,711 lines that is 3.711. The MMI is the smallest whole number of lines at or above it, 4, with epsilon 0: the metric is an exact integer, so a 4-line gain is real, and pays one step. The floor moves with the baseline: a reward version whose baseline passes 4,000 lines needs an MMI of 5, past 5,000 one of 6.

The incumbent, and the public records

The records are public, and a prefix of one plays any count of lines up to its own. A project that started below them would pay for pasting them, a few steps a submission. So the project starts at the record, credited to its holders: only a new world record pays.

The records

The world records on https://qntm.org/records, in records/records.jsonl, with thanks to their holders and to qntm, who keeps the list:

Date Holder Lines Pieces Source
2010-04-04 Atypical 11 61 https://qntm.org/hatetris#komment2579
2010-04-09 an anonymous guest at the Speed Demos Archive 17 73 http://speeddemosarchive.com/forum/index.php?topic=11523.msg321724#msg321724
2010-04-11 an anonymous guest at the Speed Demos Archive 20 80 https://qntm.org/records
2010-04-18 Ivenris 22 84 https://qntm.org/hatetris#komment2655
2010-04-26 an anonymous guest at the Speed Demos Archive 28 100 http://speeddemosarchive.com/forum/index.php?topic=11523.msg323956#msg323956
2010-05-04 Deasuke 30 104 http://slashdot.jp/comments.pl?sid=493607&cid=1758529
2017-06-06 @chromeyhex 31 106 http://twitter.com/chromeyhex
2021-06-13 knewjade 32 109 https://qntm.org/hatetris#komment60c75410f2ad6
2021-06-15 knewjade 34 114 https://qntm.org/hatetris#komment60c87ce994917
2021-06-20 knewjade 41 130 https://qntm.org/hatetris#komment60cf26f7d8c92
2021-06-27 knewjade 45 142 https://qntm.org/hatetris#komment60d852b340aa2
2021-08-23 knewjade 66 192 https://qntm.org/hatetris#komment61238cbbd3612
2022-05-30 David & Felipe 86 248 https://qntm.org/hatetris#komment6293f5024978c
2022-11-05 David & Felipe 148 402 https://qntm.org/hatetris#komment63666ca6cc1a7
2022-11-15 David & Felipe 152 412 https://qntm.org/hatetris#komment6373b447e7e3a
2022-11-19 Tim 157 420 https://qntm.org/hatetris#komment6378d0f08bff1
2022-11-23 Tim 170 455 https://qntm.org/hatetris#komment637da3c92f14a
2022-11-25 Tim 232 611 https://qntm.org/hatetris#komment6380b4e548cd5
2022-11-26 knewjade 289 752 https://qntm.org/hatetris#komment63818f793a198
2023-03-05 David & Felipe 302 789 https://qntm.org/hatetris#komment6404c2c374fee
2024-09-04 David & Felipe 366 948 https://qntm.org/hatetris#komment66d89ea487f7b
2025-04-07 David & Felipe 3,711 9,309 https://qntm.org/hatetris#komment67f413c5e5d53

The 2025 record is the starting incumbent (src/replay.txt). David & Felipe's write-ups of how they found their earlier records: https://hallofdreams.org/posts/hatetris/ and https://hallofdreams.org/posts/hatetris-2/; their search code: https://github.com/thecog19/HATETRIS-public-beamsearch.

The project has no upstream ([project].upstream left out, ADR-0004). Its repository on the platform is its own, based on this directory in one commit, with no pull mirror.

Running it

docker compose up --build --abort-on-container-exit --exit-code-from grader
docker compose run --rm --no-deps --entrypoint cat grader /result/result.json
docker compose down --volumes

The incumbent scores lines 3711, with pieces 9309 and moves 138449. arh run (the platform's CLI, cli/README.md) runs the same three commands and prints the result. To try a move string without Docker, from this directory: python -c 'import sys; sys.path.insert(0, "grader"); import hatetris; print(hatetris.replay(open("moves.txt").read().strip()).score)'.

Licences

What Source Licence
grader/hatetris.py (a port) qntm's HATETRIS, https://github.com/qntm/hatetris, Copyright (c) 2021 qntm MIT
tools/qntm_replay.py (a port) HATETRIS's replay codec (as above); base2048 3.0.0, Copyright (c) 2017 qntm; base65536 5.0.0, Copyright (c) 2021 qntm MIT
records/, src/replay.txt the record holders' published replays (the table above), via https://qntm.org/records credited to their holders
everything else this project MIT
Python 3.13 (python:3.13-slim-bookworm) Docker Hub, the images' base PSF-2.0