All projects
open source / 2026AI & Agents · Games

racing-AI

A hundred cars that cannot see the track, evolving until they can drive it.

racing-AI

The story

I saw a video about evolving controllers by breeding and mutation, and I wanted to see for myself whether something that simple really works. It does. A hundred cars start with random numbers in their heads and drive into a wall. The few that get furthest are copied, mixed and slightly mutated, and their children try again. Nobody shows them a good lap: there is no dataset, only survival.

weights in each brain
470
generations of evolution
300
unseen tracks out of 40 finished without a crash
40
average lap on those tracks
27.7 s
Trained drivers on a track none of them has ever seen.

What the car is allowed to see

This is the choice everything else depends on. Each car gets eight numbers: seven distances to the walls, cast like rays, and its own speed. No map and no idea where it is on the track, so it cannot learn a layout by heart. Whatever it ends up doing has to be actual driving.

The brain is a small network, 8 → 16 → 12 → 8 → 2, and its two outputs are the steering and the pedal. All 470 of its weights, laid end to end, are the car's genome.

  1. 1

    Race

    Every car drives six tracks generated for this generation alone. No layout is ever seen twice, and the tracks used to judge the champion come from a separate range of seeds.

  2. 2

    Score

    Finishing is a gate, not a bonus: a car that completes the lap always outranks one that does not, so lap time can never be bought with risk. Across the six tracks the score is 70% the average and 30% the worst, so consistency beats one lucky run.

  3. 3

    Breed

    The best 5 pass on untouched. The rest are children of the top 25, picked by tournaments of three, mixed gene by gene and mutated slightly. 3 random newcomers join every generation so the population never collapses on one idea.

  4. 4

    Repeat

    The mutation shrinks a little every generation, from wide exploration early on to fine tuning at the end.

From the wall to the finish line

In generation zero, almost every car crashes or goes nowhere: half a percent of the runs finish a lap. By the last fifty generations, 82% of them do, on tracks the cars had never seen until that moment.

laps finishedcrashes
100%50%
0generation300
Every run of every car, generation by generation, straight from the training log.

Braking that nobody rewarded

The physics decide what driving means here. Below about 4 units per second the steering is limited by the rack; above it, by grip, so the turning radius grows with the square of the speed. At top speed the car needs a radius of about 84 units, and the generated corners go down to about 19.

So a corner cannot be taken flat out. Nothing in the score mentions braking, and the cars learned to brake anyway, because it was the only way through a hairpin.

Picking the champion

Scores cannot be compared across generations, because the tracks change underneath them. So the saved driver is not the one with the highest score. Every ten generations the current leader races on tracks kept aside for this, and it replaces the champion only if it finishes more of them, with lap time as the tie-break. The final champion finishes all 40 without a crash, at 27.7 seconds a lap on average.

Fast enough to try things

The whole population is one set of NumPy arrays: one raycast call and one forward pass for a hundred cars at once. A generation over six tracks takes about 8 seconds on a laptop, which is what makes a 300-generation run cheap enough to try ideas on.

A run is reproducible to the byte: training with the window open and headless from the same seed produce identical populations, and resuming a run picks up the same random stream. 114 tests keep it that way.

Gallery

racing-AI · 1

Want something like this?

I can build the same thing for your product.

Tell me what you have in mind. You get an answer the same day, with a realistic scope and timeline, not a sales pitch.