Pong AI

Pong AI trains an artificial-intelligence (AI) player in the browser. Its controller is a multilayer perceptron (MLP), a small neural network evolved through repeated games of Pong.

The debug information above each agent shows the 21 neurons that make up its "brain".

Press N to hide the debug information.
Press P to cycle between three control modes: AI vs AI, AI vs human, and human vs human.
Control the left paddle with the W and S keys.
Control the right paddle with the ↑ and ↓ arrow keys.

See if you can beat the AI you trained!

The code is available on GitHub.

Technical details:
  • Macroquad renders the game through the browser's Web Graphics Library (WebGL) interface using Macroquad
  • The AI is implemented in Rust and compiled to WebAssembly to run in the browser.
  • The neural network is a 3-layer MLP with 8-16-4-1 layer arrangement.
  • Each genetic-algorithm generation contains 128 players. Browser training runs for 100 generations, with every player competing in a full round-robin tournament.
  • The mutation strategy is random Gaussian mutation with no crossover.
  • Hidden layer activations are rectified linear units (ReLU).
  • The output layer activation is a hyperbolic tangent (tanh).
  • Each player's fitness is its zero-sum score across the tournament.
  • Pre-trained champion:
    • The initial population includes a locally trained champion to reduce the work on your processor. The generations shown on screen, including the final result, are still trained in your browser through WebAssembly with a small JavaScript loader.
    • The champion came from several thousand local generations that tested tournament selection, different fitness functions and several mutation and crossover strategies. Experiments also used graphics-processor compute, but simple multithreaded processor training produced the best results for this small workload.
Acknowledgements:

This project revisits a formative collaboration with a former peer whose early contributions shaped its trajectory. The original implementation—a C++ genetic algorithm with a neural network to learn Pong—was largely his work. At the time, I lacked the technical depth to fully grasp it. He brought competitive programming rigor and algorithmic fluency that exceeded my understanding then.

Rebuilding it now in Rust serves a dual purpose: technical redemption and continued learning. The implementation uses ordinary compiler optimization, including automatic vectorization where the compiler finds suitable loops. More importantly, it’s been an exercise in understanding compilation, lowering and systems-level design—concepts I hadn’t appreciated during the original effort.

The broader arc is about catching up with the field. Back in 2015, transformers didn’t exist in the mainstream curriculum. Reconstructing this project from first principles is a way to retrace the path from classical neural networks to the architectures that define modern AI—following the breadcrumbs, step by step.