I’m fascinated by natural selection; the
idea that incredible complexity and environmental
adaptation is a consequence of small random
changes.
It should be no surprise that I’ve been
a fan of the Primer youtube channel for quite
a while.
The channel digs deep into ideas of evolution
by natural selection, and more.
I am also a fan of simulations, obviously…
so when Primer released the video titled “Simulating
Natural Selection” my programmer’s fingers
got itchy.
I like learning by playing.
I wanted to get my hands on the controls and
see what other kinds of things I could learn
from these cute, unassuming blob creatures.
That was a year ago.
Since then I got in touch with Justin and
took on the task of giving his blob creatures
a new home in a web browser.
This is the Evolution Simulator.
I tried to keep it as similar to the original
as I could, but since I had to rewrite everything
from scratch, there may be some minor differences.
Let’s go through the laws governing blob
world:
First, in any generation, every blob needs
to eat one piece of food and return to the
edge of the world to survive to the next generation.
If a blob gets two pieces of food, then it
will reproduce.
But blobs have a fixed amount of energy they
can use every day to move around finding food,
and the rate that they use up energy depends
on three traits.
The first trait is sight range.
Blobs will move in a random way until a piece
of food enters their range of vision.
Once a blob can see food, it will move straight
towards it and eat it… that is, unless another
blob beats them to it.
Which brings us to the next trait.
The speed trait is just how fast a blob can
move.
There’s not much more to say than that.
You can enable a speed indicator that makes
the faster blobs a brighter red color, as
shown here.
The third trait is size.
Here’s where things get interesting: larger
blobs can eat smaller blobs if they are at
least 20% larger… and if they are fast enough
to catch them.
I should mention one specific difference between
the Primer simulation and mine: and that has
to do with how speed works.
I noticed that really tiny blobs could move
lightning fast because their size and speed
weren’t related at all.
This looked a bit weird to me… a blob the
size of an ant shouldn’t be able to keep
up with a default sized blob under normal
circumstances.
So what I did was I coupled speed and size
together.
If a blob is larger it will be able to move
faster than a smaller blob with the same speed
value.
Think of it like how fast your limbs can move.
If you can take the same number of steps per
second as an ant, you will cover more distance
just because of the fact that you’re gigantic
compared to the ant.
Anyways, seeing farther, moving faster, and
using fellow blobs as a source of food are
certainly advantages, but each of them comes
with a cost.
As they say, there’s no such thing as a
free lunch, and these blobs pay in energy.
Every time a blob moves it loses energy proportional
to its sight range plus its size cubed times
it’s speed squared.
We could have chosen any energy cost relationship
we like, but Justin chose this energy cost
to resemble the formula for kinetic energy…
which makes a lot of sense.
When blobs manage to eat two bits of food
and return to the edge of the board, they
are able to reproduce.
This means the blob is duplicated but each
of the duplicate’s traits are bumped up
or down by a random amount.
For example, for any given blob’s offspring,
there's an equal chance of it being larger
or smaller, faster or slower, seeing farther
or being condemned to wander alone in the
darkness, unaware of the scrumptious green
rewards waiting beyond the edge of its nose.
That is to say, there’s nothing built into
the simulation that forces younger blobs to
be better at reproducing than their parents.
We don’t even know what better would be
exactly, but we don’t need to.
Given enough time, a large population’s
traits will, on average, evolve towards an
optimum for survival in the current environment.
Blobs that, by chance, have traits closer
to the optimum will have a higher chance of
reproducing, and their offspring will have
trait values closer to those successful parents
than the rest of the population.
You can get an overview of this adaptation
by looking at the trends page.
This shows how the traits of the blob population
change over time.
The brightest line is the average value of
the trait.
The region around the average is the standard
deviation; which gives you an idea of how
spread out the values are in the population.
The highest and lowest lines are the maximum
and minimum values for the trait.
They correspond to the blobs at the top and
bottom of the pack.
For example, with these parameters when we
look at sight range we can see a bunch of
generations where there’s a huge spread
in the standard deviation.
We can switch back to the world view, look
at a generation around that time and turn
on the sight range indicators to see this
trait value for every blob.
Some of these circles are really big and others
are really small.
There’s a lot of deviation in the sight
range in this generation.
But, switching back to the trends page, we
can see a bunch of generations where the standard
deviation in the sight range is small.
If we look at the blob world around that time,
we can see that the sight range circles are
roughly the same size.
If you experiment with this a bit, you can
notice some really interesting things about
how these blobs evolve.
For example, we can change how different baby
blobs will be from their parents by changing
the mutation variance in the settings.
If we have a mutation variance in the size
trait of around one, then that means baby
blobs will have a chance of being bigger or
smaller than their parents by a value of around
one.
Let’s turn up the playback speed and watch
the blobs evolve for a while.
[...]
Notice that the small blobs are usually the
last to find food.
That’s because being small is much more
energy efficient, so smaller blobs can wander
around looking for food for longer.
If we focus on one of the large blobs we can
see that all it has time to do is chase a
smaller blob and eat it before it runs out
of energy and has to return home.
A smaller blob, on the other hand, can wander
a very long time before running out of energy.
So there’s a selection pressure towards
being smaller because smaller blobs can spend
more time looking for two pieces of food.
And if we look at the trend for the size trait
we can see that it decreases from a value
of 10 down to around 8 in 600 generations.
So what happens if we decrease the mutation
variance in the size trait so that baby blobs
are less different than their parents.
Will the average size decrease slower than
before because they are mutating their size
less?
Turns out to be the opposite!
In 600 generations, the size decreases to
7 instead of 9.
So if the blobs are mutating less, why does
their average size evolve faster?
If we compare the two worlds we can see why
this could be the case.
In the first world, there were blobs of many
different sizes.
Competition was fierce and if a blob happened
to be smaller than the average, there was
a larger chance that it was small enough to
be eaten by a bigger blob.
But in this new world, where the variation
in size between blobs is small, most blobs
are roughly the same size, so there’s almost
no chance of being next to another blob that
is big enough to pose a threat.
In other words, there’s no cost in being
slightly smaller so the average will decrease
at a steady rate.
This is a good thing to keep in mind; just
because there’s a huge amount of mutation
doesn’t mean evolution happens faster.
The speed of evolution depends on the selective
pressures in the environment.
There’s something else I noticed when playing
around with this that I found really amazing.
It has to do with the age of the blobs.
The age is how many generations a blob has
existed so far.
A newly born blob, for example, will have
an age of zero and if it survives to the next
generation it will have an age of 1.
The weird thing is this: the average age of
the blobs in a generation grows to around
2, and then levels off, no matter how I change
the settings.
It does this every time.
It looks like there must be some fundamental
rule here to be discovered.
So why does this happen?
I actually think this explanation deserves
its own video, so I’ll save it for another
time.
Until then, you’re welcome to try to figure
it out for yourself.
And I’d love to hear in the comments what
kinds of behaviours and trends you notice
while playing around with this.
As usual thanks so much to those of you supporting
me on Patreon.
And I should mention that there’s another
way to support me that would actually help
me out even more.
I’ve enabled github sponsors on my projects.
If you have a github account, you can now
go to my profile or a minutelabs github repository
and click the Sponsor button.
If you sponsor me by any amount, I get every
penny of that money.
Not only that, but github will match every
donation I get through github sponsors…
which effectively doubles all donations at
no additional cost to you so I hope you consider
doing that.
If you do, let me know and I can add you to
the list of MinuteLabs beta-testers if you’d
like.
Soon enough, I’ll be releasing enhancements
to the Evolution Simulator to allow you to
change how the blobs behave even more.
So I’ll see you again, ...sooner than usual
with something new.
