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.