Files
feuerwerk/todo-notes/done/tetris-example-game.md
T
rootandClaude Opus 5 4f78c7518c Give the graph a loop, and build Tetris with it
A Tetris example project needs to draw 200 board cells and scan rows
for a full line. Neither is expressible without iteration, so the node
system gets a Repeat node plus the missing text side: Substring, Find
text and To number. The interpreter drops its data cache once per
round -- otherwise every round would recompute with the first round's
values.

Object by name takes its name as an input now, not just as a setting;
addressing "c" + index is impossible otherwise. An unconnected input
reads the stored setting, so saved projects are untouched.

The board itself is a 200-character text, "." for empty. That makes
both operations of Tetris a single expression instead of a loop, and
each frame attempts exactly one move -- rotate beats sideways beats
fall -- so the fit check exists once in the whole graph.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 19:10:41 +02:00

5.9 KiB
Raw Blame History

Nächstes spiel: Tetris

Ganz simpel halten, also wirklich nur das nötigste:

  • die möglichen shapes die es halt so gibt
  • ein zufallspawn eines dieser shapes das langsam nach unten geht
  • links/rechts pfeilstasten um zu bewegen, pfeil rauf um im uhrzeigsinn zu drehen, pfeil runter gedrückt halten um nach unten zu beschleunigen
  • eine line gefüllte line solved
  • obere grenze = game over, ansonsten ist es einfach ein endlosspiel
  • counter ui der einfach nur die gesolved lines zählt

was wir nicht brauchen:

  • "levels", sprich dass shapes schneller werden beim runterfallen
  • titlescreen oder gameover screen, wenn gameover einfach spiel stoppen
  • animationen, spezielle texturen, oder sonst irgendwelchen schnick schnack
  • e2e erweiterung zu dem projekt => dieses projekt braucht keine speziellen e2e tests die man immer wieder durchlaufen muss

habe ich irgendwas vergessen? wenn ja, rückfragen, ansonsten einfach project seed anlegen und projekt generieren

falls nodes fehlen, oder praktische nodes sinnvoll wären die noch fehlen, dürfen diese natürlich erstellt werden


Umgesetzt (2026-09-09). Projekt Tetris (2072b56583af), Seed tools/seed-tetris.mjs, gespielt von tools/smoke-tetris.mjs. Alles aus deiner Liste ist drin, nichts davon, was du ausgeschlossen hast: keine Level, kein Titel- oder Game-Over-Screen (Game Over stoppt das Spiel per Stop game), keine Animationen, keine Texturen, und keine Erweiterung der E2E-Suite — der Smoke-Lauf ist wie beim Jump-and-Run ein eigenes Skript, das nur laeuft, wenn dieses Projekt oder die Engine darunter sich aendert.

Das Brett ist ein Text. 200 Zeichen, eins pro Zelle: . fuer leer, sonst die Ziffer der Form, die dort liegengeblieben ist. Damit sind die beiden Operationen, auf denen Tetris steht, je ein einziger Ausdruck statt einer Schleife: eine Zelle ist Substring(grid, zeile·10 + spalte, 1), und eine volle Reihe zu loesen ist eine leere Reihe, vor alles darueber und darunter gejoint. Gezeichnet wird aus einem Vorrat benannter Objekte — c0…c199 fuer das Brett, p0…p3 fuer den fallenden Stein. Waehrend des Spielens wird nichts gespawnt und nichts zerstoert.

Vier neue Nodes, alle allgemein und nicht Tetris-eigen (danach gefragt, du hast (a) gewaehlt):

Repeat (flow) times → body / index / done. Der Interpreter kann seitdem Schleifen: er verwirft den Datencache pro Runde, sonst rechnete jede Runde mit den Werten der ersten.
Substring count Zeichen ab start; negatives count reicht bis zum Ende
Find text wo ein Text zuerst vorkommt, −1 wenn nicht — damit ist "Reihe voll" = kein Punkt darin
To number die fehlende Gegenrichtung zu To text

Dazu eine Aenderung an einem vorhandenen Node: Object by name nimmt den Namen jetzt als Eingang statt nur als Einstellung. Ohne das waeren 200 Zellen nicht adressierbar — die Zeichen- schleife baut "c" + index. Alte Projekte sind unberuehrt: ein gespeicherter Name liegt in params.name, und genau von dort liest ein unverbundener Eingang (eigener Test dafuer).

Der Kunstgriff, der den Graphen klein haelt: jeder Frame versucht genau einen Zug — Drehen schlaegt Seitwaerts schlaegt Fallen. Die Tasten bewegen nichts selbst, sie hinterlassen einen Wunsch (wantDx, wantRot), den der naechste Frame einloest. Dadurch gibt es die Pruefung "passen die vier Zellen dort hin?" einmal im ganzen Graphen statt einmal pro Taste. Ein um einen Frame verzoegerter Seitwaertsschritt ist bei 60 fps unsichtbar; drei Kopien derselben 30 Nodes waeren es nicht.

Wie das Landen ins Brett kommt: der gelandete Stein wird nicht noch einmal aus der Formtabelle ausgerechnet, sondern von seinen vier Zellobjekten abgelesen (Get position → Spalte/Zeile). Sie stehen genau dort, wo der Stein ist — das Zeichnen ist die einzige Stelle, die sie anfasst.

Belegt — tools/smoke-tetris.mjs, remote im echten Browser: ALL PASSED, 17 Checks.

PASS  the piece falls on its own – row 1 → 4
PASS  the left arrow moves the piece one column – 4,5,4,5 → 3,4,3,4
PASS  the up arrow turns the piece – rot 0 → 1
PASS  the board draws exactly the cells the board text names – {"lit":8,"inText":8}
PASS  a full line disappears and is counted – lines 1, bottom row "....44...."
PASS  a piece that cannot fall at the very top stops the game – stopped

Der Brett-Check ist der wichtigste: er haelt den Text gegen die Bildschirmzellen — ohne ihn koennte die Zeichenschleife irgendetwas anzeigen und alles andere trotzdem gruen sein. Fuer die volle Reihe wird die unterste Reihe vorher gefuellt, damit jeder Stein sie vollmacht, egal welcher kommt. Der Game-Over-Check wartet auf die Bedingung statt auf die Uhr — mit fester Wartezeit war er in einem von zwei Laeufen rot, und ein Check, der wuerfelt, ist keiner.

Was ich selbst entschieden habe:

  • Kein Wall-Kick. Eine Drehung, die nicht passt, findet nicht statt — sie wird nicht an der Wand vorbeigeschoben. Das ist die simple Regel, und "ganz simpel" war die Vorgabe.
  • Farbe pro Form, wie im Original. Kostet drei Nodes: die Ziffer im Bretttext sucht ihre Farbe aus einem zweiten Text (colors), acht Ziffern je Farbe.
  • Drehachse ist die Box der Form (I in 4×4, O in 2×2, Rest 3×3), nicht der Schwerpunkt. Ohne Wall-Kick ist das das Verhalten, das am wenigsten ueberrascht.
  • Game Over = ein Stein kann ganz oben (py ≤ 0) nicht einmal fallen. Kein zweiter Test beim Erscheinen, damit die Pruefung an der einen Stelle bleibt.
  • Tempo: eine Reihe pro halber Sekunde, gehaltene Pfeil-runter-Taste zehnmal so schnell. Beides steht als Variable stepTime im Inspector.

Was du wissen solltest: der Board-Container traegt 205 Objekte (Wanne + 200 Zellen + 4 Steinzellen). Im Editor sieht man davon nichts — die Szene zeigt acht Objekte, der Rest liegt im Container. Wer ihn aber oeffnet, bekommt eine lange Liste. Das ist der Preis dafuer, dass nichts gespawnt wird.