Personal
Racing Generations
Neural-network drivers that teach themselves to race — from a 2D sim to full 3D TORCS.
- Year
- 2026
- Role
- Solo — research & engineering
- Stack
- Python, NumPy, TORCS, Docker, TypeScript
The question
Can you get a car to drive well without ever telling it how? No reward shaping from a human driver, no labeled data — just a population of tiny neural networks, a fitness score, and evolution.
And the harder question: does the driver actually learn to drive, or does it just memorize one track?
What I built
A 2D top-down simulator where 100 cars, each driven by a 15→16→16→3 network (579 weights), race at once. Each car sees the world through rangefinder sensors and outputs steering, throttle and brake. After every generation the best drivers breed the next one.
The physics is a kinematic bicycle model vectorized across the whole population in a single NumPy call, and the networks run as one batched einsum per layer — so a generation of 100 cars costs about as much as one. I tested the physics against highway-env to 1e-9.
I implemented four algorithms side by side — a classic genetic algorithm, MAP-Elites, NEAT, and a 'layer evolution' mode where networks can add and remove layers. Layer evolution ended up deleting every hidden layer: the best driver is a direct sensors→controls network with just 48 parameters, and it finishes 21 of 24 tracks it has never seen. That's the driver you can switch to in the demo.
Generalization
The interesting experiment: train on one fixed track and the best driver finishes 0% of tracks it has never seen. Train on a freshly generated random track every generation and it finishes 90% of held-out tracks. A POET-style curriculum landed at 80%.
Going 3D
The successor, Evo Racing Sim, plugs the same evolution core into TORCS — a full 3D racing simulator — running in six Docker containers on Apple Silicon and talking to Python over UDP at about 110× real time. A generation of 100 full laps takes ~30 seconds.
Drivers get 19 rangefinders plus rpm and gear, control the gearbox themselves, and are scored on sector times. By generation 157 the evolved AI ran a 46.91s standing-start lap on g-track-1, beating TORCS's built-in berniw2 bot (50.41s) and within a tenth of berniw (46.82s). There's also a mode where you race a ghost of the best AI yourself.
Replaying TORCS in the browser
TORCS can't run in a web page, so the 3D demo is a recording. TORCS is deterministic in lock-step mode, so re-racing a saved driver reproduces its original race exactly. I took the best driver of generations 1, 10, 50, 157 and 912 from a later 989-generation run, raced them together as ghost cars in the same Docker image, and logged every car every 20 ms of race time.
The SCR interface never reports x, y or z, only how far along the track a car is, how far across it, and its angle to the track axis. The replay puts those back on g-track-1 as rebuilt from TORCS's own track file, elevation and banking included, the same way Evo Racing Sim's dashboard draws its 3D map. Lap times in the replay are TORCS's own. They come from a different run than the generation-157 lap above, so the numbers differ.



