A game console made of neurons

Snake, played on a tiny computer whose every clock tick is one neural network. Pure CSS, with 0 bytes of JavaScript.

score
Out of movesGame over
no moves left
Your last move took instructions.
score
Your moveGame over
1 move left
Your last move took instructions.
score
Your moveGame over
2 moves left
Your last move took instructions.
score
Your moveGame over
3 moves left
Your last move took instructions.
score
Your moveGame over
4 moves left
Your last move took instructions.
score
Your moveGame over
5 moves left
Your last move took instructions.
score
Your moveGame over
6 moves left
Your last move took instructions.
score
Your moveGame over
7 moves left
Your last move took instructions.
score
Your moveGame over
8 moves left
Your last move took instructions.
score
Your moveGame over
9 moves left
Your last move took instructions.
score
Your moveGame over
10 moves left
Your last move took instructions.
score
Your moveGame over
11 moves left
Your last move took instructions.
score
Your moveGame over
12 moves left
Your last move took instructions.
score
Your moveGame over
13 moves left
Your last move took instructions.
score
Your moveGame over
14 moves left
Your last move took instructions.
score
Your moveGame over
15 moves left
Your last move took instructions.
score
Your moveGame over
16 moves left
Your last move took instructions.
score
Your moveGame over
17 moves left
Your last move took instructions.
score
Your moveGame over
18 moves left
Your last move took instructions.
score
Your moveGame over
19 moves left
Your last move took instructions.
score
Your moveGame over
20 moves left
Your last move took instructions.
score
Your moveGame over
21 moves left
Your last move took instructions.
score
Your moveGame over
22 moves left
Your last move took instructions.
score
Your moveGame over
23 moves left
Your last move took instructions.
score
Your moveGame over
24 moves left
Your last move took instructions.
score
Your moveGame over
25 moves left
Your last move took instructions.
score
Your moveGame over
26 moves left
Your last move took instructions.
score
Your moveGame over
27 moves left
Your last move took instructions.
score
Your moveGame over
28 moves left
Your last move took instructions.
score
Your moveGame over
29 moves left
Your last move took instructions.
score
Your moveGame over
30 moves left
Your last move took instructions.
score
Your moveGame over
31 moves left
Your last move took instructions.
score
Your moveGame over
32 moves left
Your last move took instructions.
score
Your moveGame over
33 moves left
Your last move took instructions.
score
Your moveGame over
34 moves left
Your last move took instructions.
score
Your moveGame over
35 moves left
Your last move took instructions.
score
Your moveGame over
36 moves left
Your last move took instructions.
score
Your moveGame over
37 moves left
Your last move took instructions.
score
Your moveGame over
38 moves left
Your last move took instructions.
score
Your moveGame over
39 moves left
Your last move took instructions.
score
Your moveGame over
40 moves left
Your last move took instructions.
score
Your moveGame over
41 moves left
Your last move took instructions.
score
Your moveGame over
42 moves left
Your last move took instructions.
score
Your moveGame over
43 moves left
Your last move took instructions.
score
Your moveGame over
44 moves left
Your last move took instructions.
score
Your moveGame over
45 moves left
Your last move took instructions.
score
Your moveGame over
46 moves left
Your last move took instructions.
score
Your moveGame over
47 moves left
Your last move took instructions.
score
Your moveGame over
48 moves left
Your last move took instructions.
score
Your moveGame over
49 moves left
Your last move took instructions.
score
Your moveGame over
50 moves left
Your last move took instructions.
score
Your moveGame over
51 moves left
Your last move took instructions.
score
Your moveGame over
52 moves left
Your last move took instructions.
score
Your moveGame over
53 moves left
Your last move took instructions.
score
Your moveGame over
54 moves left
Your last move took instructions.
score
Your moveGame over
55 moves left
Your last move took instructions.
score
Your moveGame over
56 moves left
Your last move took instructions.
score
Your moveGame over
57 moves left
Your last move took instructions.
score
Your moveGame over
58 moves left
Your last move took instructions.
score
Your moveGame over
59 moves left
Your last move took instructions.
score
Your moveGame over
60 moves left
The console has not run yet.
How it works (for the curious)

The console's instructions

Two 8-bit registers, A and B, a program counter, and 90 bytes of memory. The cartridge is 48 instructions, each a code and a number (n a number, m a memory cell, t an instruction). Numbers wrap around at 256, memory cells at 90.

WAITstop here for goodADD mA = A + memory[m]
SYNC twait for the next button, then go on at tSUB mA = A − memory[m]
LDI nA = nADDI nA = A + n
LD mA = memory[m]WRAP nif A ≥ n: A = A − n
ST mmemory[m] = ANEXT nB = B + n (around the 90 cells)
LDX nA = memory[B + n]JMP tgo to t
STX nmemory[B + n] = AJZ tgo to t if A is 0
SETX nmemory[B] = nJNZ tgo to t if A is not 0
LDB mB = memory[m]JXNZ tgo to t if memory[B] is not 0
TABB = AINA = the button pressed (1 to 4)
TBAA = Bother codes do nothing

The memory is the screen

A 9 × 10 grid: the 8 × 8 playfield and a wall around it (the left and right walls share one column). The snake only needs the wall to be "not empty", so wall cells also hold the game's variables. An empty cell is 0, the wall 1, food 2, the head 3, and a body cell holds the address of the next piece towards the head: moving the tail is one lookup. New food goes 23 cells further on, then further again while that cell is taken.

0score1head2tail3food4new5678state910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182↑83→84↓85←86878889

The program

#instructionwhat it does
0loopINA = the button
1TAB
2LDX DELTAA = the step for that button
3ADD HEADA = the cell the head moves to
4ST NEW
5TABB = that cell
6JXNZ busynot empty? look closer
7moveLDB HEAD
8STX 0the old head points to the new one
9LDB TAIL
10LDX 0A = the cell after the tail
11ST TAIL
12SETX 0erase the old tail
13headLD NEW
14TAB
15SETX 3draw the head
16ST HEAD
17SYNC loopwait for the next button
18busyLDX 0A = what is there
19ADDI 254minus 2: food?
20JZ eat
21LD NEW
22SUB TAILthe tail moves away, so it is fine
23JNZ dead
24LD NEW
25JMP move
26eatLDB HEAD
27LD NEW
28STX 0grow: the old head points to the new one, the tail stays
29LD SCORE
30ADDI 1
31ST SCORE
32LDB FOOD
33probeNEXT STRIDEthe next place for food
34JXNZ probetaken? try further
35TBA
36ST FOOD
37SETX 2draw the food
38JMP head
39deadLDI 2
40ST STATUSgame over
41overSYNC over

One tick, as ReLUs

PartHow
fetch[PC = i] for every line, each gating that line's code and number: relu(op_i − 31·(1 − [PC = i]) − 31·waiting)
decode[op = k] for each code, from one shared row of units relu(op − k + 1)
addressm, B + n or B, each mod 90 with one unit: ⌊x / 90⌋ = round(relu(2x − 89) / 180)
memoryevery cell read through [address = j]; the written cell becomes cell − relu(cell − 255·h) + relu(data − 255·h), h = 2 − [address = j] − write
conditionsfolded into the gates: relu(x − 47·(1 − JXNZ) − 47·memory[B]) is "x if JXNZ and the cell is empty": with x the next line it falls through, and subtracted from t it jumps when the cell is not empty

One tick is 676 units. The page writes 12 ticks out as one network of 8,112 units and 51,575 weights, and runs it 3 times per move: 24,336 units per click. As a strict layered network one tick is 11 layers and 1,730 units, most of them only passing values down a layer (grey below). In CSS every unit of a step sits on the same element and can read any other directly, so the page leaves those out.

layer 1
243
layer 2
196
layer 3
102
layer 4
131
layer 5
139
layer 6
211
layer 7
388
layer 8
119
layer 9
106
layer 10
95
output
95
learnedhand-writtencarry (passes a value down a layer)

A move whose buttons haven't been pressed yet is hidden, so the browser computes nothing inside it: a click computes just that move's 36 ticks. Browsers stop nesting HTML at 512 levels; 12 ticks per network keeps the 60 moves at 360 levels.

Checked

A plain Python emulator runs the console, and a plain Python Snake checks the emulator: 5,000 games, every move. The networks match the emulator in numpy, every register and memory cell: one tick, every tick, on 3,000 random programs and 100 games; the 12-tick network after every step, on 2,000 random programs and 300 full games. Every partial sum, measured on every state of those runs, stays below 224 by a factor of more than 100, so 32-bit CSS engines are exact too. The browser test plays 12 games by clicking the arrows in Chromium, Firefox and WebKit and compares the screen, score and game over after every move.