Snake
The snake is an ordered list of grid cells with the head first. Moving means adding a new head in front. Eating decides whether the tail stays.
One tick
flowchart TD
A["Take the queued direction"] --> B["New head = current head + direction"]
B --> C{"Outside the grid or on the snake's body?"}
C -- yes --> D["Game over"]
C -- no --> E["Add the new head to the front of the list"]
E --> F{"Is it on the food?"}
F -- yes --> G["Score +1 and place new food on a random empty cell"]
F -- no --> H["Remove the tail cell"]
G --> I["Draw"]
H --> I
I --> J["Schedule the next tick"]
J --> A
Growing needs no extra step. On a normal move the snake gains a head and loses a tail, so its length stays the same. On an eating move the tail removal is skipped, so the snake is one cell longer.
Steering
flowchart LR
A["Arrow key, WASD, swipe, or d-pad"] --> B{"Is it on the axis the snake is already moving along?"}
B -- yes --> C["Ignore it"]
B -- no --> D["Queue it for the next tick"]
All four input methods go through the same check, which ignores any input along the current axis. That blocks pressing left while moving right, which would put the head onto the neck and end the game instantly. The direction is queued and applied at the start of the tick, so two quick key presses between ticks can't combine into a reversal.
Speed
The delay between ticks is 200 ms minus 6 ms per point, with a floor of 70 ms. The floor is reached at a score of 22.