Sit back, relax, and watch the Tesla learn its full self-driving job. Press [t] to train — spawns a pack of cars that learn in parallel. Press [v] to view — swaps in one car driving on the current best network, no more mutating, just showing off what it's learned. Press [space] (or click the stage) to change the track — this does confuse the NN slightly... so don't do that while it's running. Press [x] to show/hide variable/list details.
Reorganized some scripts from the old project and added the NN to the project. Credit to @Titanpai for the initial rule-based AI concept and raycasting technique — I built heavily on both. vv--------vv---------vv Note for AI devs/geeks: this is a small first-pass NN, 6 inputs → 5 hidden neurons → 1 output. Each car raycasts for itself (no separate sensor sprite): 6 evenly-spaced rays march forward 4px at a time until they hit a wall, then back off 1px at a time to refine the distance — cheap enough to run every tick with no visible lag. Those 6 normalized distances feed a hidden layer (W1/B1, tanh via (e^2x−1)/(e^2x+1)), then an output neuron (W2/B2, also tanh) steers tdir by up to ±6°/tick. Actual learning, not just noise — it's an evolution strategy, and it's parallelized: NumCars cars (adjustable on-stage, default 8) train simultaneously, each testing its own mutated copy of one shared best-known network. Score counts survival ticks. Whenever any car crashes (wall or stage edge), it checks in against the shared best: beats it → gets saved as the new best; doesn't → reloads the current best. Either way it mutates again before its next attempt, so with 8 cars racing at once you get roughly 8x the generations-per-minute of a single car doing this alone. Mutation size is adaptive, not fixed: it grows the longer it's been since the shared best last improved (so a long plateau triggers bigger, riskier jumps to escape it), and snaps back down to fine-tune the moment something actually wins. Only ~35% of weights get touched per attempt, not the whole network at once.