feat: complete tetris rewrite — flat grid, SRS rotation, ghost piece toggle
Rewrote game-tetris.ds from scratch using a single flat 200-element grid array instead of 20 separate row signals, eliminating all row dispatch chains. Added SRS-standard rotations for all 7 pieces via array lookups, full collision detection (down/left/right/rotation), line clear with slice/concat cascade, computed ghost piece with togglable visibility (G key or button), hard drop, per-piece colors, and next piece preview. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9fb65e6a77
commit
f01cd10c0a
1 changed files with 274 additions and 301 deletions
|
|
@ -1,19 +1,5 @@
|
|||
-- DreamStack Tetris — Signal Composition Showcase
|
||||
--
|
||||
-- This game demonstrates how DreamStack composes independent signal layers:
|
||||
--
|
||||
-- Layer 1: DATA SIGNALS — grid cells, piece encoding, bag randomizer
|
||||
-- Layer 2: PHYSICS SIGNALS — gravity timer, drop speed, lock delay
|
||||
-- Layer 3: INPUT SIGNALS — keyboard events mapped to commands
|
||||
-- Layer 4: DERIVED SIGNALS — ghost position, line detection, game over
|
||||
-- Layer 5: UI SIGNALS — score, level, next piece preview
|
||||
-- Layer 6: STREAM SIGNALS — real-time spectator broadcast
|
||||
--
|
||||
-- Each layer is self-contained; the reactive runtime composites them.
|
||||
--
|
||||
-- Grid: 10 wide x 20 tall. Rows g0 (top) to g19 (bottom).
|
||||
-- Cell values: 0=empty, 1=cyan(I), 2=blue(J), 3=orange(L),
|
||||
-- 4=yellow(O), 5=green(S), 6=purple(T), 7=red(Z)
|
||||
-- DreamStack Tetris
|
||||
-- Blocks fall. They collide. They freeze. Lines clear.
|
||||
--
|
||||
-- Run:
|
||||
-- Tab 1: cargo run -p ds-stream (relay)
|
||||
|
|
@ -22,44 +8,20 @@
|
|||
import { Badge } from "../registry/components/badge"
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 1: DATA SIGNALS — Frozen grid + active piece state
|
||||
-- GRID: flat 200-element array (20 rows × 10 cols)
|
||||
-- grid[row * 10 + col] = 0 (empty) or 1-7 (piece color)
|
||||
-- ================================================================
|
||||
|
||||
-- Frozen grid: 20 rows x 10 columns (row 0 = top, row 19 = bottom)
|
||||
let g0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g5 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g7 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g9 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g10 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g11 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g12 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g13 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g14 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g15 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g16 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g17 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g18 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let g19 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let grid = [0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]
|
||||
|
||||
-- Active piece: 1=I, 2=J, 3=L, 4=O, 5=S, 6=T, 7=Z
|
||||
let piece = 6
|
||||
let rotation = 0
|
||||
let px = 3
|
||||
let py = 0
|
||||
|
||||
-- Next piece for preview
|
||||
let nextPiece = 1
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 2: PHYSICS SIGNALS — Gravity, speed, level
|
||||
-- ================================================================
|
||||
|
||||
-- Game state
|
||||
let score = 0
|
||||
let lines = 0
|
||||
let level = 1
|
||||
|
|
@ -68,168 +30,157 @@ let paused = 0
|
|||
let gravityTick = 0
|
||||
let dropInterval = 24
|
||||
let lockTick = 0
|
||||
let clearDelay = 0
|
||||
let ghostY = 0
|
||||
let showGhost = 1
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 3: INPUT SIGNALS — Keyboard events
|
||||
-- PIECE SHAPES: array lookup — sd[cell][x/y][shapeIndex]
|
||||
-- Index = (piece - 1) * 4 + rotation (28 entries, pieces 1-7 × rot 0-3)
|
||||
-- SRS standard rotations for all 7 tetrominoes
|
||||
-- ================================================================
|
||||
|
||||
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowLeft" then (if px > 0 then px - 1 else px) else px))
|
||||
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowRight" then (if px < 7 then px + 1 else px) else px))
|
||||
on keydown(ev) -> rotation = if gameOver then rotation else (if paused then rotation else (if ev.key == "ArrowUp" then (rotation + 1) % 4 else rotation))
|
||||
on keydown(ev) -> py = if gameOver then py else (if paused then py else (if blocked then py else (if ev.key == "ArrowDown" then (if py < 19 then py + 1 else py) else py)))
|
||||
on keydown(ev) -> py = if gameOver then py else (if paused then py else (if blocked then py else (if ev.key == " " then (if piece == 6 then 18 else 19) else py)))
|
||||
on keydown(ev) -> paused = if ev.key == "p" then (if paused then 0 else 1) else paused
|
||||
-- Cell 0 offsets (dx, dy)
|
||||
let sd0x = [0, 2, 0, 1, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 0, 1]
|
||||
let sd0y = [1, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
|
||||
-- Cell 1 offsets
|
||||
let sd1x = [1, 2, 1, 1, 0, 2, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0, 1, 1, 0, 1, 1, 1, 0]
|
||||
let sd1y = [1, 1, 2, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1]
|
||||
-- Cell 2 offsets
|
||||
let sd2x = [2, 2, 2, 1, 1, 1, 2, 0, 1, 1, 2, 1, 0, 0, 0, 0, 0, 2, 0, 1, 1, 2, 2, 1, 1, 2, 1, 1]
|
||||
let sd2y = [1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1]
|
||||
-- Cell 3 offsets
|
||||
let sd3x = [3, 2, 3, 1, 2, 1, 2, 1, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 0]
|
||||
let sd3y = [1, 3, 2, 3, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2]
|
||||
|
||||
-- Color arrays for piece-type rendering (index 0=empty, 1-7=piece)
|
||||
let colorL = ["#171717", "#22d3ee", "#60a5fa", "#fb923c", "#facc15", "#4ade80", "#c084fc", "#f87171"]
|
||||
let colorD = ["#171717", "#06b6d4", "#3b82f6", "#f97316", "#eab308", "#22c55e", "#a855f7", "#ef4444"]
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 4: DERIVED SIGNALS — Collision, gravity, lock, line clear
|
||||
-- ================================================================
|
||||
-- COLLISION SYSTEM (decomposed into composable sub-signals)
|
||||
-- DERIVED: cell offsets from shape arrays
|
||||
-- ================================================================
|
||||
|
||||
-- Sub-signal 1: Bottom wall (piece-type dependent)
|
||||
-- T-piece stops at py=18 (foot at 19), all others at py=19
|
||||
let blockedWall = 0
|
||||
every 33 -> blockedWall = if piece == 6 then (if py >= 18 then 1 else 0) else (if py >= 19 then 1 else 0)
|
||||
let si = 0
|
||||
let c0dx = 0
|
||||
let c0dy = 0
|
||||
let c1dx = 0
|
||||
let c1dy = 0
|
||||
let c2dx = 0
|
||||
let c2dy = 0
|
||||
let c3dx = 0
|
||||
let c3dy = 0
|
||||
|
||||
-- Sub-signal 2: Top row collision — check grid[py+1] at px, px+1, px+2
|
||||
-- This is the core 3-cell check shared by ALL piece types
|
||||
let blockedTop = 0
|
||||
every 33 -> blockedTop = if py >= 19 then 0 else (if py == 18 then (if g19[px] > 0 then 1 else (if g19[px + 1] > 0 then 1 else (if g19[px + 2] > 0 then 1 else 0))) else (if py == 17 then (if g18[px] > 0 then 1 else (if g18[px + 1] > 0 then 1 else (if g18[px + 2] > 0 then 1 else 0))) else (if py == 16 then (if g17[px] > 0 then 1 else (if g17[px + 1] > 0 then 1 else (if g17[px + 2] > 0 then 1 else 0))) else (if py == 15 then (if g16[px] > 0 then 1 else (if g16[px + 1] > 0 then 1 else (if g16[px + 2] > 0 then 1 else 0))) else (if py == 14 then (if g15[px] > 0 then 1 else (if g15[px + 1] > 0 then 1 else (if g15[px + 2] > 0 then 1 else 0))) else (if py == 13 then (if g14[px] > 0 then 1 else (if g14[px + 1] > 0 then 1 else (if g14[px + 2] > 0 then 1 else 0))) else (if py == 12 then (if g13[px] > 0 then 1 else (if g13[px + 1] > 0 then 1 else (if g13[px + 2] > 0 then 1 else 0))) else (if py == 11 then (if g12[px] > 0 then 1 else (if g12[px + 1] > 0 then 1 else (if g12[px + 2] > 0 then 1 else 0))) else (if py == 10 then (if g11[px] > 0 then 1 else (if g11[px + 1] > 0 then 1 else (if g11[px + 2] > 0 then 1 else 0))) else (if py == 9 then (if g10[px] > 0 then 1 else (if g10[px + 1] > 0 then 1 else (if g10[px + 2] > 0 then 1 else 0))) else (if py == 8 then (if g9[px] > 0 then 1 else (if g9[px + 1] > 0 then 1 else (if g9[px + 2] > 0 then 1 else 0))) else (if py == 7 then (if g8[px] > 0 then 1 else (if g8[px + 1] > 0 then 1 else (if g8[px + 2] > 0 then 1 else 0))) else (if py == 6 then (if g7[px] > 0 then 1 else (if g7[px + 1] > 0 then 1 else (if g7[px + 2] > 0 then 1 else 0))) else (if py == 5 then (if g6[px] > 0 then 1 else (if g6[px + 1] > 0 then 1 else (if g6[px + 2] > 0 then 1 else 0))) else (if py == 4 then (if g5[px] > 0 then 1 else (if g5[px + 1] > 0 then 1 else (if g5[px + 2] > 0 then 1 else 0))) else (if py == 3 then (if g4[px] > 0 then 1 else (if g4[px + 1] > 0 then 1 else (if g4[px + 2] > 0 then 1 else 0))) else (if py == 2 then (if g3[px] > 0 then 1 else (if g3[px + 1] > 0 then 1 else (if g3[px + 2] > 0 then 1 else 0))) else (if py == 1 then (if g2[px] > 0 then 1 else (if g2[px + 1] > 0 then 1 else (if g2[px + 2] > 0 then 1 else 0))) else (if py == 0 then (if g1[px] > 0 then 1 else (if g1[px + 1] > 0 then 1 else (if g1[px + 2] > 0 then 1 else 0))) else 0)))))))))))))))))))
|
||||
every 33 -> si = (piece - 1) * 4 + rotation
|
||||
every 33 -> c0dx = sd0x[si]
|
||||
every 33 -> c0dy = sd0y[si]
|
||||
every 33 -> c1dx = sd1x[si]
|
||||
every 33 -> c1dy = sd1y[si]
|
||||
every 33 -> c2dx = sd2x[si]
|
||||
every 33 -> c2dy = sd2y[si]
|
||||
every 33 -> c3dx = sd3x[si]
|
||||
every 33 -> c3dy = sd3y[si]
|
||||
|
||||
-- Sub-signal 3: T-piece foot collision — check grid[py+2] at px+1
|
||||
-- Only applies to T-piece (piece==6)
|
||||
let blockedFoot = 0
|
||||
every 33 -> blockedFoot = if piece != 6 then 0 else (if py >= 18 then 0 else (if py == 17 then (if g19[px + 1] > 0 then 1 else 0) else (if py == 16 then (if g18[px + 1] > 0 then 1 else 0) else (if py == 15 then (if g17[px + 1] > 0 then 1 else 0) else (if py == 14 then (if g16[px + 1] > 0 then 1 else 0) else (if py == 13 then (if g15[px + 1] > 0 then 1 else 0) else (if py == 12 then (if g14[px + 1] > 0 then 1 else 0) else (if py == 11 then (if g13[px + 1] > 0 then 1 else 0) else (if py == 10 then (if g12[px + 1] > 0 then 1 else 0) else (if py == 9 then (if g11[px + 1] > 0 then 1 else 0) else (if py == 8 then (if g10[px + 1] > 0 then 1 else 0) else (if py == 7 then (if g9[px + 1] > 0 then 1 else 0) else (if py == 6 then (if g8[px + 1] > 0 then 1 else 0) else (if py == 5 then (if g7[px + 1] > 0 then 1 else 0) else (if py == 4 then (if g6[px + 1] > 0 then 1 else 0) else (if py == 3 then (if g5[px + 1] > 0 then 1 else 0) else (if py == 2 then (if g4[px + 1] > 0 then 1 else 0) else (if py == 1 then (if g3[px + 1] > 0 then 1 else 0) else (if py == 0 then (if g2[px + 1] > 0 then 1 else 0) else 0)))))))))))))))))))
|
||||
-- ================================================================
|
||||
-- COLLISION: can the piece move down?
|
||||
-- Check floor bounds + grid occupancy for all 4 cells
|
||||
-- ================================================================
|
||||
|
||||
-- Sub-signal 4: I-piece 4th cell collision — check grid[py+1] at px+3
|
||||
-- Only applies to I-piece (piece==1)
|
||||
let blockedI4 = 0
|
||||
every 33 -> blockedI4 = if piece != 1 then 0 else (if py >= 19 then 0 else (if py == 18 then (if g19[px + 3] > 0 then 1 else 0) else (if py == 17 then (if g18[px + 3] > 0 then 1 else 0) else (if py == 16 then (if g17[px + 3] > 0 then 1 else 0) else (if py == 15 then (if g16[px + 3] > 0 then 1 else 0) else (if py == 14 then (if g15[px + 3] > 0 then 1 else 0) else (if py == 13 then (if g14[px + 3] > 0 then 1 else 0) else (if py == 12 then (if g13[px + 3] > 0 then 1 else 0) else (if py == 11 then (if g12[px + 3] > 0 then 1 else 0) else (if py == 10 then (if g11[px + 3] > 0 then 1 else 0) else (if py == 9 then (if g10[px + 3] > 0 then 1 else 0) else (if py == 8 then (if g9[px + 3] > 0 then 1 else 0) else (if py == 7 then (if g8[px + 3] > 0 then 1 else 0) else (if py == 6 then (if g7[px + 3] > 0 then 1 else 0) else (if py == 5 then (if g6[px + 3] > 0 then 1 else 0) else (if py == 4 then (if g5[px + 3] > 0 then 1 else 0) else (if py == 3 then (if g4[px + 3] > 0 then 1 else 0) else (if py == 2 then (if g3[px + 3] > 0 then 1 else 0) else (if py == 1 then (if g2[px + 3] > 0 then 1 else 0) else (if py == 0 then (if g1[px + 3] > 0 then 1 else 0) else 0))))))))))))))))))))
|
||||
|
||||
-- Combined blocked signal: any sub-signal triggers block
|
||||
let blocked = 0
|
||||
every 33 -> blocked = if blockedWall then 1 else (if blockedTop then 1 else (if blockedFoot then 1 else (if blockedI4 then 1 else 0)))
|
||||
every 33 -> blocked = if py + c0dy + 1 >= 20 then 1 else (if py + c1dy + 1 >= 20 then 1 else (if py + c2dy + 1 >= 20 then 1 else (if py + c3dy + 1 >= 20 then 1 else (if grid[(py + c0dy + 1) * 10 + px + c0dx] > 0 then 1 else (if grid[(py + c1dy + 1) * 10 + px + c1dx] > 0 then 1 else (if grid[(py + c2dy + 1) * 10 + px + c2dx] > 0 then 1 else (if grid[(py + c3dy + 1) * 10 + px + c3dx] > 0 then 1 else 0)))))))
|
||||
|
||||
-- Left collision: wall + grid
|
||||
let leftOk = 0
|
||||
every 33 -> leftOk = if px + c0dx - 1 < 0 then 0 else (if px + c1dx - 1 < 0 then 0 else (if px + c2dx - 1 < 0 then 0 else (if px + c3dx - 1 < 0 then 0 else (if grid[(py + c0dy) * 10 + px + c0dx - 1] > 0 then 0 else (if grid[(py + c1dy) * 10 + px + c1dx - 1] > 0 then 0 else (if grid[(py + c2dy) * 10 + px + c2dx - 1] > 0 then 0 else (if grid[(py + c3dy) * 10 + px + c3dx - 1] > 0 then 0 else 1)))))))
|
||||
|
||||
-- Right collision: wall + grid
|
||||
let rightOk = 0
|
||||
every 33 -> rightOk = if px + c0dx + 1 >= 10 then 0 else (if px + c1dx + 1 >= 10 then 0 else (if px + c2dx + 1 >= 10 then 0 else (if px + c3dx + 1 >= 10 then 0 else (if grid[(py + c0dy) * 10 + px + c0dx + 1] > 0 then 0 else (if grid[(py + c1dy) * 10 + px + c1dx + 1] > 0 then 0 else (if grid[(py + c2dy) * 10 + px + c2dx + 1] > 0 then 0 else (if grid[(py + c3dy) * 10 + px + c3dx + 1] > 0 then 0 else 1)))))))
|
||||
|
||||
-- Rotation collision: check if next rotation fits
|
||||
let nrot = 0
|
||||
let nsi = 0
|
||||
let nc0dx = 0
|
||||
let nc0dy = 0
|
||||
let nc1dx = 0
|
||||
let nc1dy = 0
|
||||
let nc2dx = 0
|
||||
let nc2dy = 0
|
||||
let nc3dx = 0
|
||||
let nc3dy = 0
|
||||
let rotOk = 0
|
||||
|
||||
every 33 -> nrot = (rotation + 1) % 4
|
||||
every 33 -> nsi = (piece - 1) * 4 + nrot
|
||||
every 33 -> nc0dx = sd0x[nsi]
|
||||
every 33 -> nc0dy = sd0y[nsi]
|
||||
every 33 -> nc1dx = sd1x[nsi]
|
||||
every 33 -> nc1dy = sd1y[nsi]
|
||||
every 33 -> nc2dx = sd2x[nsi]
|
||||
every 33 -> nc2dy = sd2y[nsi]
|
||||
every 33 -> nc3dx = sd3x[nsi]
|
||||
every 33 -> nc3dy = sd3y[nsi]
|
||||
every 33 -> rotOk = if px + nc0dx < 0 then 0 else (if px + nc0dx >= 10 then 0 else (if py + nc0dy >= 20 then 0 else (if px + nc1dx < 0 then 0 else (if px + nc1dx >= 10 then 0 else (if py + nc1dy >= 20 then 0 else (if px + nc2dx < 0 then 0 else (if px + nc2dx >= 10 then 0 else (if py + nc2dy >= 20 then 0 else (if px + nc3dx < 0 then 0 else (if px + nc3dx >= 10 then 0 else (if py + nc3dy >= 20 then 0 else (if grid[(py + nc0dy) * 10 + px + nc0dx] > 0 then 0 else (if grid[(py + nc1dy) * 10 + px + nc1dx] > 0 then 0 else (if grid[(py + nc2dy) * 10 + px + nc2dx] > 0 then 0 else (if grid[(py + nc3dy) * 10 + px + nc3dx] > 0 then 0 else 1)))))))))))))))
|
||||
|
||||
-- ================================================================
|
||||
-- GHOST: compute landing position (try to push ghostY down 19 times)
|
||||
-- ================================================================
|
||||
|
||||
every 33 -> ghostY = py
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
every 33 -> ghostY = if ghostY + c0dy + 1 >= 20 then ghostY else (if ghostY + c1dy + 1 >= 20 then ghostY else (if ghostY + c2dy + 1 >= 20 then ghostY else (if ghostY + c3dy + 1 >= 20 then ghostY else (if grid[(ghostY + c0dy + 1) * 10 + px + c0dx] > 0 then ghostY else (if grid[(ghostY + c1dy + 1) * 10 + px + c1dx] > 0 then ghostY else (if grid[(ghostY + c2dy + 1) * 10 + px + c2dx] > 0 then ghostY else (if grid[(ghostY + c3dy + 1) * 10 + px + c3dx] > 0 then ghostY else ghostY + 1)))))))
|
||||
|
||||
-- ================================================================
|
||||
-- INPUT: keyboard controls
|
||||
-- ================================================================
|
||||
|
||||
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowLeft" then (if leftOk then px - 1 else px) else px))
|
||||
on keydown(ev) -> px = if gameOver then px else (if paused then px else (if ev.key == "ArrowRight" then (if rightOk then px + 1 else px) else px))
|
||||
on keydown(ev) -> rotation = if gameOver then rotation else (if paused then rotation else (if ev.key == "ArrowUp" then (if rotOk then nrot else rotation) else rotation))
|
||||
on keydown(ev) -> py = if gameOver then py else (if paused then py else (if ev.key == "ArrowDown" then (if blocked then py else py + 1) else (if ev.key == " " then ghostY else py)))
|
||||
on keydown(ev) -> paused = if ev.key == "p" then (if paused then 0 else 1) else paused
|
||||
on keydown(ev) -> showGhost = if ev.key == "g" then (if showGhost then 0 else 1) else showGhost
|
||||
|
||||
-- ================================================================
|
||||
-- PHYSICS: gravity pulls pieces down, contact freezes them
|
||||
-- ================================================================
|
||||
|
||||
-- Gravity tick
|
||||
every 33 -> gravityTick = if paused then gravityTick else (if gameOver then gravityTick else gravityTick + 1)
|
||||
|
||||
-- Auto-drop: py can go up to 19 (not 18) — blocked wall handles per-piece limits
|
||||
every 33 -> py = if paused then py else (if gameOver then py else (if blocked then py else (if gravityTick > dropInterval then (if py < 19 then py + 1 else py) else py)))
|
||||
-- Auto-drop: gravity pulls piece down
|
||||
every 33 -> py = if paused then py else (if gameOver then py else (if blocked then py else (if gravityTick > dropInterval then py + 1 else py)))
|
||||
every 33 -> gravityTick = if gravityTick > dropInterval then 0 else gravityTick
|
||||
|
||||
-- Lock detection: start counting when blocked
|
||||
-- Lock: when blocked (contact!), count frames then freeze
|
||||
every 33 -> lockTick = if blocked then lockTick + 1 else 0
|
||||
|
||||
-- ── Freeze piece into grid at py position on lock ──
|
||||
-- Top 3 cells go into grid[py], T-piece bottom cell into grid[py+1]
|
||||
-- Full grid coverage: rows 0-19
|
||||
-- ================================================================
|
||||
-- FREEZE: on contact, write piece cells into grid
|
||||
-- ================================================================
|
||||
|
||||
-- Freeze top cells (3 per row, all 20 rows)
|
||||
every 33 -> g0[px] = if lockTick == 3 then (if py == 0 then piece else g0[px]) else g0[px]
|
||||
every 33 -> g0[px + 1] = if lockTick == 3 then (if py == 0 then piece else g0[px + 1]) else g0[px + 1]
|
||||
every 33 -> g0[px + 2] = if lockTick == 3 then (if py == 0 then piece else g0[px + 2]) else g0[px + 2]
|
||||
every 33 -> g1[px] = if lockTick == 3 then (if py == 1 then piece else g1[px]) else g1[px]
|
||||
every 33 -> g1[px + 1] = if lockTick == 3 then (if py == 1 then piece else g1[px + 1]) else g1[px + 1]
|
||||
every 33 -> g1[px + 2] = if lockTick == 3 then (if py == 1 then piece else g1[px + 2]) else g1[px + 2]
|
||||
every 33 -> g2[px] = if lockTick == 3 then (if py == 2 then piece else g2[px]) else g2[px]
|
||||
every 33 -> g2[px + 1] = if lockTick == 3 then (if py == 2 then piece else g2[px + 1]) else g2[px + 1]
|
||||
every 33 -> g2[px + 2] = if lockTick == 3 then (if py == 2 then piece else g2[px + 2]) else g2[px + 2]
|
||||
every 33 -> g3[px] = if lockTick == 3 then (if py == 3 then piece else g3[px]) else g3[px]
|
||||
every 33 -> g3[px + 1] = if lockTick == 3 then (if py == 3 then piece else g3[px + 1]) else g3[px + 1]
|
||||
every 33 -> g3[px + 2] = if lockTick == 3 then (if py == 3 then piece else g3[px + 2]) else g3[px + 2]
|
||||
every 33 -> g4[px] = if lockTick == 3 then (if py == 4 then piece else g4[px]) else g4[px]
|
||||
every 33 -> g4[px + 1] = if lockTick == 3 then (if py == 4 then piece else g4[px + 1]) else g4[px + 1]
|
||||
every 33 -> g4[px + 2] = if lockTick == 3 then (if py == 4 then piece else g4[px + 2]) else g4[px + 2]
|
||||
every 33 -> g5[px] = if lockTick == 3 then (if py == 5 then piece else g5[px]) else g5[px]
|
||||
every 33 -> g5[px + 1] = if lockTick == 3 then (if py == 5 then piece else g5[px + 1]) else g5[px + 1]
|
||||
every 33 -> g5[px + 2] = if lockTick == 3 then (if py == 5 then piece else g5[px + 2]) else g5[px + 2]
|
||||
every 33 -> g6[px] = if lockTick == 3 then (if py == 6 then piece else g6[px]) else g6[px]
|
||||
every 33 -> g6[px + 1] = if lockTick == 3 then (if py == 6 then piece else g6[px + 1]) else g6[px + 1]
|
||||
every 33 -> g6[px + 2] = if lockTick == 3 then (if py == 6 then piece else g6[px + 2]) else g6[px + 2]
|
||||
every 33 -> g7[px] = if lockTick == 3 then (if py == 7 then piece else g7[px]) else g7[px]
|
||||
every 33 -> g7[px + 1] = if lockTick == 3 then (if py == 7 then piece else g7[px + 1]) else g7[px + 1]
|
||||
every 33 -> g7[px + 2] = if lockTick == 3 then (if py == 7 then piece else g7[px + 2]) else g7[px + 2]
|
||||
every 33 -> g8[px] = if lockTick == 3 then (if py == 8 then piece else g8[px]) else g8[px]
|
||||
every 33 -> g8[px + 1] = if lockTick == 3 then (if py == 8 then piece else g8[px + 1]) else g8[px + 1]
|
||||
every 33 -> g8[px + 2] = if lockTick == 3 then (if py == 8 then piece else g8[px + 2]) else g8[px + 2]
|
||||
every 33 -> g9[px] = if lockTick == 3 then (if py == 9 then piece else g9[px]) else g9[px]
|
||||
every 33 -> g9[px + 1] = if lockTick == 3 then (if py == 9 then piece else g9[px + 1]) else g9[px + 1]
|
||||
every 33 -> g9[px + 2] = if lockTick == 3 then (if py == 9 then piece else g9[px + 2]) else g9[px + 2]
|
||||
every 33 -> g10[px] = if lockTick == 3 then (if py == 10 then piece else g10[px]) else g10[px]
|
||||
every 33 -> g10[px + 1] = if lockTick == 3 then (if py == 10 then piece else g10[px + 1]) else g10[px + 1]
|
||||
every 33 -> g10[px + 2] = if lockTick == 3 then (if py == 10 then piece else g10[px + 2]) else g10[px + 2]
|
||||
every 33 -> g11[px] = if lockTick == 3 then (if py == 11 then piece else g11[px]) else g11[px]
|
||||
every 33 -> g11[px + 1] = if lockTick == 3 then (if py == 11 then piece else g11[px + 1]) else g11[px + 1]
|
||||
every 33 -> g11[px + 2] = if lockTick == 3 then (if py == 11 then piece else g11[px + 2]) else g11[px + 2]
|
||||
every 33 -> g12[px] = if lockTick == 3 then (if py == 12 then piece else g12[px]) else g12[px]
|
||||
every 33 -> g12[px + 1] = if lockTick == 3 then (if py == 12 then piece else g12[px + 1]) else g12[px + 1]
|
||||
every 33 -> g12[px + 2] = if lockTick == 3 then (if py == 12 then piece else g12[px + 2]) else g12[px + 2]
|
||||
every 33 -> g13[px] = if lockTick == 3 then (if py == 13 then piece else g13[px]) else g13[px]
|
||||
every 33 -> g13[px + 1] = if lockTick == 3 then (if py == 13 then piece else g13[px + 1]) else g13[px + 1]
|
||||
every 33 -> g13[px + 2] = if lockTick == 3 then (if py == 13 then piece else g13[px + 2]) else g13[px + 2]
|
||||
every 33 -> g14[px] = if lockTick == 3 then (if py == 14 then piece else g14[px]) else g14[px]
|
||||
every 33 -> g14[px + 1] = if lockTick == 3 then (if py == 14 then piece else g14[px + 1]) else g14[px + 1]
|
||||
every 33 -> g14[px + 2] = if lockTick == 3 then (if py == 14 then piece else g14[px + 2]) else g14[px + 2]
|
||||
every 33 -> g15[px] = if lockTick == 3 then (if py == 15 then piece else g15[px]) else g15[px]
|
||||
every 33 -> g15[px + 1] = if lockTick == 3 then (if py == 15 then piece else g15[px + 1]) else g15[px + 1]
|
||||
every 33 -> g15[px + 2] = if lockTick == 3 then (if py == 15 then piece else g15[px + 2]) else g15[px + 2]
|
||||
every 33 -> g16[px] = if lockTick == 3 then (if py == 16 then piece else g16[px]) else g16[px]
|
||||
every 33 -> g16[px + 1] = if lockTick == 3 then (if py == 16 then piece else g16[px + 1]) else g16[px + 1]
|
||||
every 33 -> g16[px + 2] = if lockTick == 3 then (if py == 16 then piece else g16[px + 2]) else g16[px + 2]
|
||||
every 33 -> g17[px] = if lockTick == 3 then (if py == 17 then piece else g17[px]) else g17[px]
|
||||
every 33 -> g17[px + 1] = if lockTick == 3 then (if py == 17 then piece else g17[px + 1]) else g17[px + 1]
|
||||
every 33 -> g17[px + 2] = if lockTick == 3 then (if py == 17 then piece else g17[px + 2]) else g17[px + 2]
|
||||
every 33 -> g18[px] = if lockTick == 3 then (if py == 18 then piece else g18[px]) else g18[px]
|
||||
every 33 -> g18[px + 1] = if lockTick == 3 then (if py == 18 then piece else g18[px + 1]) else g18[px + 1]
|
||||
every 33 -> g18[px + 2] = if lockTick == 3 then (if py == 18 then piece else g18[px + 2]) else g18[px + 2]
|
||||
every 33 -> g19[px] = if lockTick == 3 then (if py == 19 then piece else g19[px]) else g19[px]
|
||||
every 33 -> g19[px + 1] = if lockTick == 3 then (if py == 19 then piece else g19[px + 1]) else g19[px + 1]
|
||||
every 33 -> g19[px + 2] = if lockTick == 3 then (if py == 19 then piece else g19[px + 2]) else g19[px + 2]
|
||||
every 33 -> grid[(py + c0dy) * 10 + px + c0dx] = if lockTick == 3 then piece else grid[(py + c0dy) * 10 + px + c0dx]
|
||||
every 33 -> grid[(py + c1dy) * 10 + px + c1dx] = if lockTick == 3 then piece else grid[(py + c1dy) * 10 + px + c1dx]
|
||||
every 33 -> grid[(py + c2dy) * 10 + px + c2dx] = if lockTick == 3 then piece else grid[(py + c2dy) * 10 + px + c2dx]
|
||||
every 33 -> grid[(py + c3dy) * 10 + px + c3dx] = if lockTick == 3 then piece else grid[(py + c3dy) * 10 + px + c3dx]
|
||||
|
||||
-- Freeze T-piece bottom center cell into grid[py+1] (all rows)
|
||||
every 33 -> g1[px + 1] = if lockTick == 3 then (if py == 0 then (if piece == 6 then 6 else g1[px + 1]) else g1[px + 1]) else g1[px + 1]
|
||||
every 33 -> g2[px + 1] = if lockTick == 3 then (if py == 1 then (if piece == 6 then 6 else g2[px + 1]) else g2[px + 1]) else g2[px + 1]
|
||||
every 33 -> g3[px + 1] = if lockTick == 3 then (if py == 2 then (if piece == 6 then 6 else g3[px + 1]) else g3[px + 1]) else g3[px + 1]
|
||||
every 33 -> g4[px + 1] = if lockTick == 3 then (if py == 3 then (if piece == 6 then 6 else g4[px + 1]) else g4[px + 1]) else g4[px + 1]
|
||||
every 33 -> g5[px + 1] = if lockTick == 3 then (if py == 4 then (if piece == 6 then 6 else g5[px + 1]) else g5[px + 1]) else g5[px + 1]
|
||||
every 33 -> g6[px + 1] = if lockTick == 3 then (if py == 5 then (if piece == 6 then 6 else g6[px + 1]) else g6[px + 1]) else g6[px + 1]
|
||||
every 33 -> g7[px + 1] = if lockTick == 3 then (if py == 6 then (if piece == 6 then 6 else g7[px + 1]) else g7[px + 1]) else g7[px + 1]
|
||||
every 33 -> g8[px + 1] = if lockTick == 3 then (if py == 7 then (if piece == 6 then 6 else g8[px + 1]) else g8[px + 1]) else g8[px + 1]
|
||||
every 33 -> g9[px + 1] = if lockTick == 3 then (if py == 8 then (if piece == 6 then 6 else g9[px + 1]) else g9[px + 1]) else g9[px + 1]
|
||||
every 33 -> g10[px + 1] = if lockTick == 3 then (if py == 9 then (if piece == 6 then 6 else g10[px + 1]) else g10[px + 1]) else g10[px + 1]
|
||||
every 33 -> g11[px + 1] = if lockTick == 3 then (if py == 10 then (if piece == 6 then 6 else g11[px + 1]) else g11[px + 1]) else g11[px + 1]
|
||||
every 33 -> g12[px + 1] = if lockTick == 3 then (if py == 11 then (if piece == 6 then 6 else g12[px + 1]) else g12[px + 1]) else g12[px + 1]
|
||||
every 33 -> g13[px + 1] = if lockTick == 3 then (if py == 12 then (if piece == 6 then 6 else g13[px + 1]) else g13[px + 1]) else g13[px + 1]
|
||||
every 33 -> g14[px + 1] = if lockTick == 3 then (if py == 13 then (if piece == 6 then 6 else g14[px + 1]) else g14[px + 1]) else g14[px + 1]
|
||||
every 33 -> g15[px + 1] = if lockTick == 3 then (if py == 14 then (if piece == 6 then 6 else g15[px + 1]) else g15[px + 1]) else g15[px + 1]
|
||||
every 33 -> g16[px + 1] = if lockTick == 3 then (if py == 15 then (if piece == 6 then 6 else g16[px + 1]) else g16[px + 1]) else g16[px + 1]
|
||||
every 33 -> g17[px + 1] = if lockTick == 3 then (if py == 16 then (if piece == 6 then 6 else g17[px + 1]) else g17[px + 1]) else g17[px + 1]
|
||||
every 33 -> g18[px + 1] = if lockTick == 3 then (if py == 17 then (if piece == 6 then 6 else g18[px + 1]) else g18[px + 1]) else g18[px + 1]
|
||||
every 33 -> g19[px + 1] = if lockTick == 3 then (if py == 18 then (if piece == 6 then 6 else g19[px + 1]) else g19[px + 1]) else g19[px + 1]
|
||||
|
||||
-- Freeze I-piece 4th cell into grid[py] at px+3 (all rows)
|
||||
every 33 -> g0[px + 3] = if lockTick == 3 then (if py == 0 then (if piece == 1 then 1 else g0[px + 3]) else g0[px + 3]) else g0[px + 3]
|
||||
every 33 -> g1[px + 3] = if lockTick == 3 then (if py == 1 then (if piece == 1 then 1 else g1[px + 3]) else g1[px + 3]) else g1[px + 3]
|
||||
every 33 -> g2[px + 3] = if lockTick == 3 then (if py == 2 then (if piece == 1 then 1 else g2[px + 3]) else g2[px + 3]) else g2[px + 3]
|
||||
every 33 -> g3[px + 3] = if lockTick == 3 then (if py == 3 then (if piece == 1 then 1 else g3[px + 3]) else g3[px + 3]) else g3[px + 3]
|
||||
every 33 -> g4[px + 3] = if lockTick == 3 then (if py == 4 then (if piece == 1 then 1 else g4[px + 3]) else g4[px + 3]) else g4[px + 3]
|
||||
every 33 -> g5[px + 3] = if lockTick == 3 then (if py == 5 then (if piece == 1 then 1 else g5[px + 3]) else g5[px + 3]) else g5[px + 3]
|
||||
every 33 -> g6[px + 3] = if lockTick == 3 then (if py == 6 then (if piece == 1 then 1 else g6[px + 3]) else g6[px + 3]) else g6[px + 3]
|
||||
every 33 -> g7[px + 3] = if lockTick == 3 then (if py == 7 then (if piece == 1 then 1 else g7[px + 3]) else g7[px + 3]) else g7[px + 3]
|
||||
every 33 -> g8[px + 3] = if lockTick == 3 then (if py == 8 then (if piece == 1 then 1 else g8[px + 3]) else g8[px + 3]) else g8[px + 3]
|
||||
every 33 -> g9[px + 3] = if lockTick == 3 then (if py == 9 then (if piece == 1 then 1 else g9[px + 3]) else g9[px + 3]) else g9[px + 3]
|
||||
every 33 -> g10[px + 3] = if lockTick == 3 then (if py == 10 then (if piece == 1 then 1 else g10[px + 3]) else g10[px + 3]) else g10[px + 3]
|
||||
every 33 -> g11[px + 3] = if lockTick == 3 then (if py == 11 then (if piece == 1 then 1 else g11[px + 3]) else g11[px + 3]) else g11[px + 3]
|
||||
every 33 -> g12[px + 3] = if lockTick == 3 then (if py == 12 then (if piece == 1 then 1 else g12[px + 3]) else g12[px + 3]) else g12[px + 3]
|
||||
every 33 -> g13[px + 3] = if lockTick == 3 then (if py == 13 then (if piece == 1 then 1 else g13[px + 3]) else g13[px + 3]) else g13[px + 3]
|
||||
every 33 -> g14[px + 3] = if lockTick == 3 then (if py == 14 then (if piece == 1 then 1 else g14[px + 3]) else g14[px + 3]) else g14[px + 3]
|
||||
every 33 -> g15[px + 3] = if lockTick == 3 then (if py == 15 then (if piece == 1 then 1 else g15[px + 3]) else g15[px + 3]) else g15[px + 3]
|
||||
every 33 -> g16[px + 3] = if lockTick == 3 then (if py == 16 then (if piece == 1 then 1 else g16[px + 3]) else g16[px + 3]) else g16[px + 3]
|
||||
every 33 -> g17[px + 3] = if lockTick == 3 then (if py == 17 then (if piece == 1 then 1 else g17[px + 3]) else g17[px + 3]) else g17[px + 3]
|
||||
every 33 -> g18[px + 3] = if lockTick == 3 then (if py == 18 then (if piece == 1 then 1 else g18[px + 3]) else g18[px + 3]) else g18[px + 3]
|
||||
every 33 -> g19[px + 3] = if lockTick == 3 then (if py == 19 then (if piece == 1 then 1 else g19[px + 3]) else g19[px + 3]) else g19[px + 3]
|
||||
|
||||
-- Spawn new piece after lock
|
||||
-- Spawn new piece after freeze
|
||||
every 33 -> piece = if lockTick == 3 then nextPiece else piece
|
||||
every 33 -> nextPiece = if lockTick == 3 then (gravityTick % 7 + 1) else nextPiece
|
||||
every 33 -> py = if lockTick == 3 then 0 else py
|
||||
|
|
@ -237,202 +188,224 @@ every 33 -> px = if lockTick == 3 then 3 else px
|
|||
every 33 -> rotation = if lockTick == 3 then 0 else rotation
|
||||
every 33 -> score = if lockTick == 3 then score + 10 else score
|
||||
|
||||
-- Line clear: row 19 full (check 5 sample cells)
|
||||
every 33 -> score = if g19[0] > 0 then (if g19[2] > 0 then (if g19[4] > 0 then (if g19[6] > 0 then (if g19[8] > 0 then score + 100 else score) else score) else score) else score) else score
|
||||
every 33 -> lines = if g19[0] > 0 then (if g19[2] > 0 then (if g19[4] > 0 then (if g19[6] > 0 then (if g19[8] > 0 then lines + 1 else lines) else lines) else lines) else lines) else lines
|
||||
-- ================================================================
|
||||
-- LINE CLEAR: detect full rows, cascade with slice/concat
|
||||
-- ================================================================
|
||||
|
||||
-- Shift rows down on clear: copy row 18 into row 19
|
||||
every 33 -> g19[0] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[0] else g19[0]) else g19[0]) else g19[0]
|
||||
every 33 -> g19[1] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[1] else g19[1]) else g19[1]) else g19[1]
|
||||
every 33 -> g19[2] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[2] else g19[2]) else g19[2]) else g19[2]
|
||||
every 33 -> g19[3] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[3] else g19[3]) else g19[3]) else g19[3]
|
||||
every 33 -> g19[4] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[4] else g19[4]) else g19[4]) else g19[4]
|
||||
every 33 -> g19[5] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[5] else g19[5]) else g19[5]) else g19[5]
|
||||
every 33 -> g19[6] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[6] else g19[6]) else g19[6]) else g19[6]
|
||||
every 33 -> g19[7] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[7] else g19[7]) else g19[7]) else g19[7]
|
||||
every 33 -> g19[8] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[8] else g19[8]) else g19[8]) else g19[8]
|
||||
every 33 -> g19[9] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[9] else g19[9]) else g19[9]) else g19[9]
|
||||
-- Row fullness: check all 10 cells per row
|
||||
let f0 = 0
|
||||
let f1 = 0
|
||||
let f2 = 0
|
||||
let f3 = 0
|
||||
let f4 = 0
|
||||
let f5 = 0
|
||||
let f6 = 0
|
||||
let f7 = 0
|
||||
let f8 = 0
|
||||
let f9 = 0
|
||||
let f10 = 0
|
||||
let f11 = 0
|
||||
let f12 = 0
|
||||
let f13 = 0
|
||||
let f14 = 0
|
||||
let f15 = 0
|
||||
let f16 = 0
|
||||
let f17 = 0
|
||||
let f18 = 0
|
||||
let f19 = 0
|
||||
|
||||
-- Level up
|
||||
every 33 -> f0 = if grid[0] > 0 then (if grid[1] > 0 then (if grid[2] > 0 then (if grid[3] > 0 then (if grid[4] > 0 then (if grid[5] > 0 then (if grid[6] > 0 then (if grid[7] > 0 then (if grid[8] > 0 then (if grid[9] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f1 = if grid[10] > 0 then (if grid[11] > 0 then (if grid[12] > 0 then (if grid[13] > 0 then (if grid[14] > 0 then (if grid[15] > 0 then (if grid[16] > 0 then (if grid[17] > 0 then (if grid[18] > 0 then (if grid[19] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f2 = if grid[20] > 0 then (if grid[21] > 0 then (if grid[22] > 0 then (if grid[23] > 0 then (if grid[24] > 0 then (if grid[25] > 0 then (if grid[26] > 0 then (if grid[27] > 0 then (if grid[28] > 0 then (if grid[29] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f3 = if grid[30] > 0 then (if grid[31] > 0 then (if grid[32] > 0 then (if grid[33] > 0 then (if grid[34] > 0 then (if grid[35] > 0 then (if grid[36] > 0 then (if grid[37] > 0 then (if grid[38] > 0 then (if grid[39] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f4 = if grid[40] > 0 then (if grid[41] > 0 then (if grid[42] > 0 then (if grid[43] > 0 then (if grid[44] > 0 then (if grid[45] > 0 then (if grid[46] > 0 then (if grid[47] > 0 then (if grid[48] > 0 then (if grid[49] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f5 = if grid[50] > 0 then (if grid[51] > 0 then (if grid[52] > 0 then (if grid[53] > 0 then (if grid[54] > 0 then (if grid[55] > 0 then (if grid[56] > 0 then (if grid[57] > 0 then (if grid[58] > 0 then (if grid[59] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f6 = if grid[60] > 0 then (if grid[61] > 0 then (if grid[62] > 0 then (if grid[63] > 0 then (if grid[64] > 0 then (if grid[65] > 0 then (if grid[66] > 0 then (if grid[67] > 0 then (if grid[68] > 0 then (if grid[69] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f7 = if grid[70] > 0 then (if grid[71] > 0 then (if grid[72] > 0 then (if grid[73] > 0 then (if grid[74] > 0 then (if grid[75] > 0 then (if grid[76] > 0 then (if grid[77] > 0 then (if grid[78] > 0 then (if grid[79] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f8 = if grid[80] > 0 then (if grid[81] > 0 then (if grid[82] > 0 then (if grid[83] > 0 then (if grid[84] > 0 then (if grid[85] > 0 then (if grid[86] > 0 then (if grid[87] > 0 then (if grid[88] > 0 then (if grid[89] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f9 = if grid[90] > 0 then (if grid[91] > 0 then (if grid[92] > 0 then (if grid[93] > 0 then (if grid[94] > 0 then (if grid[95] > 0 then (if grid[96] > 0 then (if grid[97] > 0 then (if grid[98] > 0 then (if grid[99] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f10 = if grid[100] > 0 then (if grid[101] > 0 then (if grid[102] > 0 then (if grid[103] > 0 then (if grid[104] > 0 then (if grid[105] > 0 then (if grid[106] > 0 then (if grid[107] > 0 then (if grid[108] > 0 then (if grid[109] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f11 = if grid[110] > 0 then (if grid[111] > 0 then (if grid[112] > 0 then (if grid[113] > 0 then (if grid[114] > 0 then (if grid[115] > 0 then (if grid[116] > 0 then (if grid[117] > 0 then (if grid[118] > 0 then (if grid[119] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f12 = if grid[120] > 0 then (if grid[121] > 0 then (if grid[122] > 0 then (if grid[123] > 0 then (if grid[124] > 0 then (if grid[125] > 0 then (if grid[126] > 0 then (if grid[127] > 0 then (if grid[128] > 0 then (if grid[129] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f13 = if grid[130] > 0 then (if grid[131] > 0 then (if grid[132] > 0 then (if grid[133] > 0 then (if grid[134] > 0 then (if grid[135] > 0 then (if grid[136] > 0 then (if grid[137] > 0 then (if grid[138] > 0 then (if grid[139] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f14 = if grid[140] > 0 then (if grid[141] > 0 then (if grid[142] > 0 then (if grid[143] > 0 then (if grid[144] > 0 then (if grid[145] > 0 then (if grid[146] > 0 then (if grid[147] > 0 then (if grid[148] > 0 then (if grid[149] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f15 = if grid[150] > 0 then (if grid[151] > 0 then (if grid[152] > 0 then (if grid[153] > 0 then (if grid[154] > 0 then (if grid[155] > 0 then (if grid[156] > 0 then (if grid[157] > 0 then (if grid[158] > 0 then (if grid[159] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f16 = if grid[160] > 0 then (if grid[161] > 0 then (if grid[162] > 0 then (if grid[163] > 0 then (if grid[164] > 0 then (if grid[165] > 0 then (if grid[166] > 0 then (if grid[167] > 0 then (if grid[168] > 0 then (if grid[169] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f17 = if grid[170] > 0 then (if grid[171] > 0 then (if grid[172] > 0 then (if grid[173] > 0 then (if grid[174] > 0 then (if grid[175] > 0 then (if grid[176] > 0 then (if grid[177] > 0 then (if grid[178] > 0 then (if grid[179] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f18 = if grid[180] > 0 then (if grid[181] > 0 then (if grid[182] > 0 then (if grid[183] > 0 then (if grid[184] > 0 then (if grid[185] > 0 then (if grid[186] > 0 then (if grid[187] > 0 then (if grid[188] > 0 then (if grid[189] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
every 33 -> f19 = if grid[190] > 0 then (if grid[191] > 0 then (if grid[192] > 0 then (if grid[193] > 0 then (if grid[194] > 0 then (if grid[195] > 0 then (if grid[196] > 0 then (if grid[197] > 0 then (if grid[198] > 0 then (if grid[199] > 0 then 1 else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0) else 0
|
||||
|
||||
-- Find bottommost full row
|
||||
let clearRow = -1
|
||||
every 33 -> clearRow = if f19 then 19 else (if f18 then 18 else (if f17 then 17 else (if f16 then 16 else (if f15 then 15 else (if f14 then 14 else (if f13 then 13 else (if f12 then 12 else (if f11 then 11 else (if f10 then 10 else (if f9 then 9 else (if f8 then 8 else (if f7 then 7 else (if f6 then 6 else (if f5 then 5 else (if f4 then 4 else (if f3 then 3 else (if f2 then 2 else (if f1 then 1 else (if f0 then 0 else -1)))))))))))))))))))
|
||||
|
||||
-- Clear row: slice out the full row, prepend empty row
|
||||
every 33 -> clearDelay = if clearRow >= 0 then clearDelay + 1 else 0
|
||||
every 33 -> grid = if clearDelay == 2 then concat([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], concat(slice(grid, 0, clearRow * 10), slice(grid, (clearRow + 1) * 10, 200))) else grid
|
||||
every 33 -> score = if clearDelay == 2 then score + 100 else score
|
||||
every 33 -> lines = if clearDelay == 2 then lines + 1 else lines
|
||||
every 33 -> clearDelay = if clearDelay == 2 then 0 else clearDelay
|
||||
|
||||
-- Level and speed
|
||||
every 33 -> level = if lines > 0 then (lines / 10 + 1) else 1
|
||||
every 33 -> dropInterval = if level > 9 then 3 else (27 - level * 3)
|
||||
|
||||
-- Game over: any cell in row 0 filled
|
||||
every 33 -> gameOver = if g0[3] > 0 then 1 else (if g0[4] > 0 then 1 else (if g0[5] > 0 then 1 else gameOver))
|
||||
-- Game over: spawn area occupied
|
||||
every 33 -> gameOver = if grid[3] > 0 then 1 else (if grid[4] > 0 then 1 else (if grid[5] > 0 then 1 else (if grid[6] > 0 then 1 else gameOver)))
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 5: SOUND SIGNALS
|
||||
-- SOUND
|
||||
-- ================================================================
|
||||
|
||||
every 33 -> play_tone(if lockTick == 3 then 220 else 0, 80)
|
||||
every 33 -> play_tone(if gameOver then 110 else 0, 500, "sawtooth")
|
||||
|
||||
-- ================================================================
|
||||
-- LAYER 6: STREAM SIGNALS — Spectator broadcast
|
||||
-- STREAM: spectator broadcast
|
||||
-- ================================================================
|
||||
|
||||
stream tetris on "ws://localhost:9100/peer/tetris" {
|
||||
mode: signal,
|
||||
output: piece, rotation, px, py, nextPiece, score, lines, level, gameOver, paused, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11, g12, g13, g14, g15, g16, g17, g18, g19
|
||||
output: piece, rotation, px, py, nextPiece, score, lines, level, gameOver, paused, grid
|
||||
}
|
||||
|
||||
-- ================================================================
|
||||
-- VIEW: All 6 signal layers composited into one display
|
||||
-- VIEW
|
||||
-- ================================================================
|
||||
|
||||
view tetris_game = column [
|
||||
text "DreamStack Tetris" { variant: "title" }
|
||||
text "Signal Composition Demo" { variant: "subtitle" }
|
||||
|
||||
-- Status bar (Layer 5 UI signals <- Layer 2 physics signals)
|
||||
row [
|
||||
Badge { label: "Score: {score}", variant: "success" }
|
||||
Badge { label: "Lines: {lines}", variant: "info" }
|
||||
Badge { label: "Level: {level}", variant: "warning" }
|
||||
Badge { label: "Next: {nextPiece}", variant: "default" }
|
||||
]
|
||||
|
||||
row [
|
||||
-- Main Board: 300x600 (10x20 cells at 30px each)
|
||||
-- Main Board: 300x600
|
||||
stack { style: "position:relative; width:300px; height:600px; background:linear-gradient(180deg,#0a0a1a,#111133); border:2px solid #334155; border-radius:12px; overflow:hidden; box-shadow:0 0 60px rgba(99,102,241,0.15)" } [
|
||||
|
||||
-- Grid lines (subtle, UI-only signals)
|
||||
-- Grid lines
|
||||
for r in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] ->
|
||||
column { style: "position:absolute; width:300px; height:1px; top:{r * 30}px; background:rgba(99,102,241,0.08)" } []
|
||||
for k in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:1px; height:600px; left:{k * 30}px; background:rgba(99,102,241,0.08)" } []
|
||||
|
||||
-- Frozen grid: all 20 rows (Layer 1 data -> Layer 5 UI)
|
||||
-- Frozen grid: row 0
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:1px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g0[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:1px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[c]]}; opacity:{if grid[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 1
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:31px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g1[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:31px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[10 + c]]}; opacity:{if grid[10 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 2
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:61px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g2[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:61px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[20 + c]]}; opacity:{if grid[20 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 3
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:91px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g3[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:91px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[30 + c]]}; opacity:{if grid[30 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 4
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:121px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g4[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:121px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[40 + c]]}; opacity:{if grid[40 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 5
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:151px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g5[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:151px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[50 + c]]}; opacity:{if grid[50 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 6
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:181px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g6[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:181px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[60 + c]]}; opacity:{if grid[60 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 7
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:211px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g7[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:211px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[70 + c]]}; opacity:{if grid[70 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 8
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:241px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g8[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:241px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[80 + c]]}; opacity:{if grid[80 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 9
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:271px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g9[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:271px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[90 + c]]}; opacity:{if grid[90 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 10
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:301px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g10[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:301px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[100 + c]]}; opacity:{if grid[100 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 11
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:331px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g11[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:331px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[110 + c]]}; opacity:{if grid[110 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 12
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:361px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g12[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; top:361px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[120 + c]]}; opacity:{if grid[120 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 13
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:391px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[130 + c]]}; opacity:{if grid[130 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 14
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:421px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[140 + c]]}; opacity:{if grid[140 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 15
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:451px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[150 + c]]}; opacity:{if grid[150 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 16
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:481px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[160 + c]]}; opacity:{if grid[160 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 17
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:511px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[170 + c]]}; opacity:{if grid[170 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 18
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:541px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[180 + c]]}; opacity:{if grid[180 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
-- Row 19
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:571px; left:{c * 30 + 1}px; border-radius:4px; background:{colorD[grid[190 + c]]}; opacity:{if grid[190 + c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(99,102,241,0.3)" } []
|
||||
|
||||
-- Frozen grid: row 13
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:391px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g13[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
-- Ghost piece: shows where piece will land
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c0dy) * 30 + 1}px; left:{(px + c0dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c1dy) * 30 + 1}px; left:{(px + c1dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c2dy) * 30 + 1}px; left:{(px + c2dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed {colorD[piece]}; opacity:{if showGhost then 0.3 else 0}; top:{(ghostY + c3dy) * 30 + 1}px; left:{(px + c3dx) * 30 + 1}px" } []
|
||||
|
||||
-- Frozen grid: row 14
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:421px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g14[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Frozen grid: row 15
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:451px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g15[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Frozen grid: row 16
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:481px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g16[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Frozen grid: row 17
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:511px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g17[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Frozen grid: row 18
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:541px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g18[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Frozen grid: row 19 (bottom)
|
||||
for c in [0,1,2,3,4,5,6,7,8,9] ->
|
||||
column { style: "position:absolute; width:28px; height:28px; top:571px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g19[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
|
||||
|
||||
-- Active piece: 4 cells (Layer 1 data + Layer 3 input -> Layer 5 UI)
|
||||
-- Cell 0: top-left of piece
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{py * 30 + 1}px; left:{(if piece == 5 then px + 1 else px) * 30 + 1}px" } []
|
||||
|
||||
-- Cell 1
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{py * 30 + 1}px; left:{(if piece == 2 then px else px + 1) * 30 + 1}px" } []
|
||||
|
||||
-- Cell 2
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{py * 30 + 1}px; left:{(px + 2) * 30 + 1}px" } []
|
||||
|
||||
-- Cell 3 (T-piece foot at py+1, I-piece 4th cell at py)
|
||||
-- Only visible for T-piece (piece==6) and I-piece (piece==1)
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; opacity:{if piece == 6 then 1 else (if piece == 1 then 1 else 0)}; top:{(if piece == 1 then py else py + 1) * 30 + 1}px; left:{(if piece == 1 then px + 3 else (if piece == 6 then px + 1 else px + 2)) * 30 + 1}px" } []
|
||||
|
||||
-- Ghost piece (Layer 4 derived -> Layer 5 UI)
|
||||
-- Shows where piece will land (row 18)
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed rgba(168,85,247,0.3); top:{18 * 30 + 1}px; left:{px * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed rgba(168,85,247,0.3); top:{18 * 30 + 1}px; left:{(px + 1) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; border:2px dashed rgba(168,85,247,0.3); top:{18 * 30 + 1}px; left:{(px + 2) * 30 + 1}px" } []
|
||||
-- Active piece: 4 cells positioned by offsets
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c0dy) * 30 + 1}px; left:{(px + c0dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c1dy) * 30 + 1}px; left:{(px + c1dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c2dy) * 30 + 1}px; left:{(px + c2dx) * 30 + 1}px" } []
|
||||
column { style: "position:absolute; width:28px; height:28px; border-radius:4px; background:{colorL[piece]}; box-shadow:0 0 12px rgba(168,85,247,0.5); transition:left 0.05s,top 0.05s; top:{(py + c3dy) * 30 + 1}px; left:{(px + c3dx) * 30 + 1}px" } []
|
||||
]
|
||||
|
||||
-- Side panel
|
||||
column [
|
||||
-- Next piece preview (Layer 1 data -> Layer 5 UI)
|
||||
text "NEXT" { variant: "subtitle" }
|
||||
stack { style: "position:relative; width:120px; height:90px; background:#0f0f23; border-radius:8px; border:1px solid #334155" } [
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:20px; left:15px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 6px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:20px; left:41px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 6px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:20px; left:67px; background:linear-gradient(180deg,#c084fc,#a855f7); box-shadow:0 0 6px rgba(168,85,247,0.4)" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:46px; left:41px; background:linear-gradient(180deg,#c084fc,#a855f7); opacity:{if nextPiece == 6 then 1 else (if nextPiece == 4 then 1 else 0)}" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd0y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd0x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd1y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd1x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd2y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd2x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
|
||||
column { style: "position:absolute; width:24px; height:24px; border-radius:3px; top:{sd3y[(nextPiece - 1) * 4] * 26 + 10}px; left:{sd3x[(nextPiece - 1) * 4] * 26 + 10}px; background:{colorL[nextPiece]}" } []
|
||||
]
|
||||
|
||||
-- Stats (Layer 2 physics -> Layer 5 UI)
|
||||
text "STATS" { variant: "subtitle" }
|
||||
text "Score: {score}"
|
||||
text "Lines: {lines}"
|
||||
text "Level: {level}"
|
||||
text "Speed: {dropInterval}" { variant: "muted" }
|
||||
text "Ticks: {gravityTick}" { variant: "muted" }
|
||||
|
||||
-- Signal debug panel (live values)
|
||||
text "SIGNALS" { variant: "subtitle" }
|
||||
text "piece:{piece} px:{px} py:{py}" { variant: "muted" }
|
||||
text "rot:{rotation} blk:{blocked}" { variant: "muted" }
|
||||
text "lock:{lockTick} grav:{gravityTick}" { variant: "muted" }
|
||||
text "score:{score} lines:{lines}" { variant: "muted" }
|
||||
text "level:{level} speed:{dropInterval}" { variant: "muted" }
|
||||
text "g13:{g13}" { variant: "muted" }
|
||||
text "g14:{g14}" { variant: "muted" }
|
||||
text "g15:{g15}" { variant: "muted" }
|
||||
text "g16:{g16}" { variant: "muted" }
|
||||
text "g17:{g17}" { variant: "muted" }
|
||||
text "g18:{g18}" { variant: "muted" }
|
||||
text "g19:{g19}" { variant: "muted" }
|
||||
text "DEBUG" { variant: "subtitle" }
|
||||
text "piece:{piece} rot:{rotation}" { variant: "muted" }
|
||||
text "px:{px} py:{py}" { variant: "muted" }
|
||||
text "blk:{blocked} lock:{lockTick}" { variant: "muted" }
|
||||
text "si:{si} clr:{clearRow}" { variant: "muted" }
|
||||
]
|
||||
]
|
||||
|
||||
-- Controls (Layer 3 input -> signal writes)
|
||||
-- Controls
|
||||
row [
|
||||
button (if paused then "Resume" else "Pause") {
|
||||
click: paused = if paused then 0 else 1,
|
||||
variant: "primary"
|
||||
}
|
||||
button "Left" { click: px = if px > 0 then px - 1 else px, variant: "secondary" }
|
||||
button "Right" { click: px = if px < 7 then px + 1 else px, variant: "secondary" }
|
||||
button "Drop" { click: py = if blocked then py else (if piece == 6 then 18 else 19), variant: "secondary" }
|
||||
button "Rotate" { click: rotation = (rotation + 1) % 4, variant: "secondary" }
|
||||
button "Left" { click: px = if leftOk then px - 1 else px, variant: "secondary" }
|
||||
button "Right" { click: px = if rightOk then px + 1 else px, variant: "secondary" }
|
||||
button "Rotate" { click: rotation = if rotOk then nrot else rotation, variant: "secondary" }
|
||||
button "Drop" { click: py = ghostY, variant: "secondary" }
|
||||
button (if showGhost then "Ghost: ON" else "Ghost: OFF") { click: showGhost = if showGhost then 0 else 1, variant: "outline" }
|
||||
button "Reset" {
|
||||
click: score = 0; lines = 0; level = 1; gameOver = 0; paused = 0; piece = 6; nextPiece = 1; px = 3; py = 0; rotation = 0; g16 = [0,0,0,0,0,0,0,0,0,0]; g17 = [0,0,0,0,0,0,0,0,0,0]; g18 = [0,0,0,0,0,0,0,0,0,0]; g19 = [0,0,0,0,0,0,0,0,0,0],
|
||||
click: score = 0; lines = 0; level = 1; gameOver = 0; paused = 0; piece = 6; nextPiece = 1; px = 3; py = 0; rotation = 0; grid = [0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0],
|
||||
variant: "destructive"
|
||||
}
|
||||
]
|
||||
|
||||
when gameOver > 0 -> text "GAME OVER - Score: {score}, Lines: {lines}" { variant: "title" }
|
||||
|
||||
text "Arrow keys: Move/Rotate | Space: Hard drop | P: Pause" { variant: "muted" }
|
||||
text "Streaming: 6 signal layers composited" { variant: "muted" }
|
||||
when gameOver > 0 -> text "GAME OVER — Score: {score}" { variant: "title" }
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue