Snake Genetics
A neural network learns to play Snake with no training data and no backpropagation — just generations of selection, crossover, and mutation.
C++ built in 2023 · rewritten in Rust in 2025
No labels, no gradients — just survival.
Snake Genetics evolves a population of snakes, each controlled by a small feed-forward neural network, to play the classic game on its own. Every snake is born with a brain full of random weights, and nothing decides which weights survive except how well that snake actually plays.
Each generation, hundreds of snakes play a full game at once. The strongest performers are picked through fitness-weighted roulette selection, paired up, and crossed over to produce the next generation's brains, with a small chance of random mutation along the way. After a few hundred generations, snakes that once wandered straight into walls are reliably chasing food instead.
Three ways to look at a snake game
A vision module turns raw game state into the network's input vector. The simplest encoding just checks for danger directly left, ahead and right of the head and the angle toward the food; wider encodings look further down each direction and add distance to the walls and to the snake's own body, all normalized so the network never has to guess how big the board is.
A hand-rolled feed-forward network
Both versions implement matrices and a feed-forward network from scratch — no ML library involved. Every layer multiplies by a weight matrix, adds a bias, and squashes the result through a sigmoid. By default there are zero hidden layers, so vision feeds straight into the three outputs and the whole "brain" is a single matrix multiplication.
Hidden layers are fully configurable — the network takes an array of layer sizes — but the plain, layer-less version turned out to already be enough to learn to play well.
Breeding the next generation
Once every snake has finished its game, the top slice of the population — 5% by default — is kept as potential parents. Two parents are drawn per child through fitness-weighted roulette selection, and the child's weight matrices are assembled by taking each individual weight from one parent or the other at random: uniform crossover applied directly to the brain.
Random resets, and a fitness function that hates loops
Every weight has a small independent chance of being thrown out and replaced with a fresh random value, which is what keeps the population from settling too early. The fitness function needed its own trick too: early populations discovered that spinning in tight loops was an easy way to survive without ever finding food, so any snake whose moves are overwhelmingly one-directional gets its fitness docked for it.
Three ways to look at the board
Same snake, same moment — switch encodings to see exactly what it can and can't perceive. All three agree on one thing: turning right right now would be fatal.
Checks the single cell to its left, ahead, and to its right: wall or body, or free? Fast, but blind beyond the very next step.
- Leftfree1
- Frontfree1
- Rightown body0
- Food angle-0.51
food is slightly left of forward
Same snake, two languages, two years apart
C++ — learning genetic algorithms
The genetic algorithm came first. The goal in 2023 was to actually understand evolution-based learning — fitness, selection, crossover, mutation — built entirely by hand, with no neural network library and no shortcuts. It renders through SFML, splits a population of hundreds of snakes across every CPU core with std::thread for each generation, and plots the average and best score per generation with matplotlib-cpp.
Rust — learning a language
Two years later, wanting to actually learn Rust rather than just read about it — and well aware of how much potential the language has — I rebuilt the exact same project from scratch instead of picking something new. A familiar problem meant the borrow checker, not the algorithm, was the thing I had to fight. It swaps SFML for macroquad, trades the manual threading for a plain sequential loop, and lets you replay the best snake's run afterward, speeding up or slowing down playback with the arrow keys.
- C++17
- Rust
- SFML
- macroquad
- Genetic Algorithm
- Neural Network