Nov 12, 2026 · Rukshan Dias

A neural network that learns Snake

Snake-NN: Neural Network Plays Snake

Key result
32.5 avg apples (greedy, 30 games)
Key result
65 best training game
Key result
963 weights
Key result
25 s CPU training
Key result
$0 hosting
Snake-NN live demo in the new paper-and-ink design: the trained agent mid-game next to the 'What the network sees' network diagram with active inputs and Q-values.
Snake-NN live demo in the new paper-and-ink design: the trained agent mid-game next to the 'What the network sees' network diagram with active inputs and Q-values.
01

Summary

I built a neural network that teaches itself to play Snake using only NumPy: the forward pass, loss, backpropagation and optimiser are all written by hand. After 400 games and about 25 seconds of CPU training it averages 32.5 apples in greedy play, with a best training game of 65. It runs live in the browser, costs $0 to host, and lets visitors watch the agent go from random to competent.

Stack

Training
Python and NumPy
Demo
Plain JavaScript and canvas
Deployment
GitHub and a free static host (Netlify)
02

Problem and goal

Most computer science portfolios carry the same Titanic and house-price notebooks, which show that someone can call a library. I wanted a project that shows I understand how a model actually learns, and that a recruiter can open and understand in under a minute.

The goal was a learning agent built with no ML framework, published as a live link, for $0.

  • No frameworkNo PyTorch, TensorFlow or autograd.
  • No compute spendTrained on a laptop CPU, no GPU.
  • No hosting spendStatic files only, no backend or database.
  • No dependencies at runtimeInference is two matrix multiplies in the browser.
03

Approach

The agent sees 11 yes/no signals instead of raw pixels, and picks one of 3 moves. A tiny state keeps the network small enough to train in seconds on a CPU.

Network architecture: 11 inputs, 64 hidden neurons, 3 outputsEleven input signals in three groups (danger 3, heading 4, food 4) connect to 64 ReLU hidden neurons, which connect to three Q-value outputs: straight, turn right and turn left. 963 weights in total.Input11Hidden64 · ReLUOutput3Danger3 signalsHeading4 signalsFood4 signalsStraightQ-valueTurn rightQ-valueTurn leftQ-value11×64 + 64 + 64×3 + 3 = 963 weights
Agent design
ComponentDesign
Inputs (11)Danger ahead, right, left (3)Heading right, down, left, up (4)Food left, right, up, down (4)
Actions (3)Go straight, turn right, turn left
Reward+10 for eating, -10 for crashing or starving (step limit of 100 times the snake length)
Network11 inputs, 64 hidden neurons (ReLU), 3 outputs, 963 weights
Board20 by 20 grid

The network outputs a Q-value for each move, meaning how good that move is expected to be, and the agent plays the highest. NumPy only was a deliberate constraint: writing every gradient by hand forces a real understanding of backprop.

04

Training

The agent learns with Q-learning: after each move it nudges its prediction for that move toward the reward it got plus the best value it expects next. The error then flows backwards through both layers, which is backprop.

Q-learning target

y equals r plus gamma times the max over a prime of Q of s prime, a prime.

Loss gradient

The partial derivative of L with respect to Q equals 2 times Q of s, a minus y.

The gradients are written by hand, then updated with a hand-written Adam optimiser.

train.py · backward passPython
dq[idx, a] = 2 * (q[idx, a] - y) / ndW2 = h.T @ dqdh = (dq @ W2.T) * (h > 0)   # through ReLUdW1 = x.T @ dh
Training settings
SettingValue
Discount (gamma)0.9
OptimiserAdam, learning rate 0.001
Replay memory100,000 transitions
UpdatesOne per move, plus 4 batches of 512 after every game
ExplorationRandom moves start at 80% and fall to 0% over 90 games
Games400, about 25 seconds on a CPU

I kept the method deliberately simple, with no target network, so every moving part can be explained in an interview.

05

Results

The agent stays near zero while it explores, then jumps once exploration ends: the average goes from 0.6 apples at game 75 to 25.9 by game 125, and settles around 30.

Average score, last 25 games

Training run, 400 games
Average score over the last 25 games during trainingLine chart. Game 25: 0.1, Game 75: 0.6, Game 100: 8.8, Game 125: 25.9, Game 250: 31.7, Game 400: 30.0. Exploration ends at game 90.01020300100200300400Gameexploration ends0.10.68.825.931.730.0
Average score over the last 25 games, by game
Game2575100125250400
Avg score0.10.68.825.931.730.0

The best game during training scored 65. Over 30 greedy games with the final weights (no random moves), the mean was 32.5 and the maximum was 55.

06

Product and UI

The demo is designed to show learning, not just a final score. It uses a paper-and-ink look: a warm near-black background, cream text, a coral accent, an editorial serif headline and monospace labels, with each panel numbered like a figure in a paper.

Snake-NN live demo in the new paper-and-ink design: the trained agent mid-game next to the 'What the network sees' network diagram with active inputs and Q-values.
Snake-NN live demo in the new paper-and-ink design: the trained agent mid-game next to the 'What the network sees' network diagram with active inputs and Q-values.
  • Checkpoint switcher: visitors can play the untrained network, the game 25 and game 80 versions, and the final one, and see the behaviour change.
  • Network view (Fig. 2): input neurons light up as the snake senses danger and food, and the three outputs show the live Q-value for each move.
  • Training chart (Fig. 3): score per game with a 10-game moving average, next to the best training game, the greedy average over 30 games and the weight count.
  • Speed and pause controls: 1×, 2×, 5× and 12× speed, space bar to pause, R to restart.
  • How it works notes: three short cards covering the forward pass, the Q-learning target and the hand-written backprop.
  • Responsive layout: works on a phone as well as a desktop.

The trained weights are embedded in a single index.html of about 100 KB, so there is no server, no API and nothing to break.

07

Shipping at $0

Training runs once on a laptop and writes the weights to JSON. A small build script embeds them in the page, so the finished site is plain static files. The code lives in a public GitHub repo, and a free static host (Netlify) deploys it from the main branch with no build command.

Running costs
ItemCost
Training compute$0 (laptop CPU)
Hosting$0 (free static hosting)
Domain$0 (default subdomain)
Backend and databaseNone needed
08

What I learned and what's next

What I learned

  • Replay memory is what makes learning stable: training on one move at a time alone was too noisy.
  • Checkpoints tell the story better than a final score, so the demo lets visitors replay each stage.
  • A small, well-chosen state (11 signals) can beat a complex one when compute is limited.

What's next

  • Add a target network and compare results across several seeds.
  • Add features that see the snake's own body, such as free space and distance to the tail, to break the plateau near 30.
  • Let visitors train the network live in the browser.
  • Add a simple rule-based baseline to show how much the network adds.

Watch it go from random to competent

Switch checkpoints in the live demo, or read the code on GitHub.

Back to all projects