Lab ·

Evolving Boids - Nature of Code

A flock of boids with sliders for every force, and a second version where the boids carry DNA and evolve. Two p5.js sketches from the Nature of Code course.

A flock of boids that chase a target, and then the same flock where the boids carry DNA and evolve: the ones that eat more get to have children. Both are p5.js sketches I made for the Nature of Code course on Kadenze by Daniel Shiffman, the same course as the generated sakura. The code is on GitHub: boids and evolving.

Boids

The course builds this up in two sessions. First vectors and forces: position, velocity and acceleration as p5.Vectors, and Newton's second law (acceleration is force divided by mass) so that heavy things are harder to push around. Then steering behaviours, a kind of force pioneered by Craig Reynolds. A steering force moves an object according to its own goals. Seeking a target, wandering, avoiding obstacles. Combine a few of them, each looking only at its neighbours, and you get flocking.

Every boid follows three rules, plus one of my own:

  • Separation: steer away from neighbours that are too close.
  • Alignment: steer the same way as your neighbours.
  • Cohesion: steer towards the middle of your neighbours.
  • Pursuit: chase a target, aiming where it will be instead of where it is.

The target isn't fixed. It's pulled around by an invisible attractor in the middle of the canvas, so the flock keeps chasing something that keeps swinging back. Click the canvas to teleport the target. The sliders at the bottom scale each rule (and max speed and max force), so you can feel what each one does on its own.

Making them evolve

The next session covers genetic algorithms: variation, selection, heredity. Take the key ideas of Darwinian evolution and run them in a simulation.

The sliders are the obvious thing to evolve. So I removed them and gave each boid its own DNA, a set of genes that holds the values the sliders used to hold: separation, alignment, cohesion, pursuit, max speed, max force and mass.

The rules of the world are simple:

  • 100 boids start with random DNA.
  • Everyone has a health of 200 that drains a little every frame. At zero, you die. Health also fades the boid's colour, so you can see who is about to go.
  • Touching the target gives you +100 health.
  • The target is no longer a passive thing to chase. It still gets pulled towards the attractor, but now it also flees from the boids.
  • At any moment, a boid has a tiny chance (0.08% per frame) to reproduce. The child starts at the parent's position with a copy of its DNA, and the copy can mutate: there's a 50% chance that one of its genes gets swapped for a new random value.

There's no fitness function and nobody picks the winners. Boids that happen to be good at catching a target that runs away eat more, live longer and so have more time to reproduce. A panel in the corner shows the average value of each gene, so you can watch the population drift. Press Enter to start over.

What happens

The population shrinks fast. In the runs I watched, it dropped from 100 to somewhere around 30 within the first minute, and then hovered there. The averages in the panel drift too, towards boids that are faster and chase harder.

It's a very loose version of the real thing. Reproduction is asexual, so there's no crossover between two parents, and the world is small: one target, one way to get food. Whatever the boids evolve into is mostly an answer to a target that runs away from them. 🤷‍♂️

Press Enter a few times and compare the averages after a minute. I'd be curious whether you get the same winners.