Introduction
For this first simulation, I made the most basic ecosystem I could think of. Little bits of green food appear at random, and a single type of creature moves around at random, eating any food it comes across. Creatures use up energy every turn and gain energy when they eat. If they run out of energy they die, when they have enough energy, they split into two. Blue creatures have lots of energy; red creatures are low on energy.
The code for this simulation and all the others in this series is here.
Simulation details
The simulation is updated in discrete steps, called "ticks" approximately once every 20 milliseconds.
Food
Each tick there is a 10% chance that a piece of food will appear in a random place in the world. Food contains 500 units of energy.
Movement
Creatures move in the direction they are pointing 0.2 pixels per tick. There is a 5% chance a creature will change its direction each tick. This give creatures a more life-like movement than if they were moving completely randomly. When a creature touches a piece of food, it eats it, gaining its energy. Currently, creatures cannot interact with other creatures and pass straight through one another. If a creature moves off the screen, it reappears on the opposite side of the screen.
Metabolism
Each tick, creatures metabolise 1 unit of their energy, to represent energy lost in moving and staying alive. If a creature's energy drops to 0, then it dies. If it eats some food, then it gains 500 units of energy.
Reproduction
If a creature has more than 1000 units of energy, it splits into two creatures, with each getting half the energy.
Population dynamics
If you run the simulation and track what happens, it will be different each time due to the randomness of food production and creature movement, but it will likely follow a similar pattern to this. (Or sometimes the population dies off before it can get started.)
At the start, the creature population is very small, while the amount of food is relatively high. The number of creature increases exponentially while there's plenty of food, but eventually there are so many creatures that they eat food faster than it appears. The amount of food suddenly decreases quite quickly, and is shortly followed by the creature population crashing. Once the population becomes low enough, the food can grow faster than it's eaten and the cycle can continue.
Despite the creature population crashing, it never get as low as the initial population, so subsequent cycles are less extreme, and the system is relatively stable.
Population predictions
When making simulations I tend to tweak its parameters fairly randomly to see which give interesting results. But it makes sense, especially in a simple simulation like this, to think a bit more carefully about how the parameters will affect the outcome. In this simulation all the creatures are equal, so who lives and who dies is completely random. Nonetheless, we can make some predictions about the population as a whole.
To start with, we can try to predict the average population size by thinking about the energy in the system. The simulated world is not closed: it has energy coming in, in the form of food, and energy leaving in creatures' metabolism.
Stable creature population
The amount of energy entering the system each tick, $\color{green}{E_{in}}$, is, on average, the probability of food appearing times the amount of energy in the food.
$\color{green}{E_{in} = 0.1 \times 500 = 50}$
The amount of energy leaving the system each tick, $\color{red}{E_{out}}$ is equal to the number of creatures, $n$, times the metabolic rate, $1$.
$\color{red}{E_{out} = n \times 1 = n}$
The simulation will be stable when the change in energy, $\Delta E$, is 0. This happens when the number of creatures, $n$, is 50.
$\Delta E = \color{green}{E_{in}} - \color{red}{E_{out}} = \color{green}{50} - \color{red}{n}$
So if there are more than 50 creatures, the energy in the system will fall over time. To start with, energy could be lost as creatures eat food and burn the energy, but eventually the number of creatures must decrease.
If there are fewer than 50 creatures, then the energy in the system increases over time. This means that food grows faster than it's eaten, so the amount of food in the system increases. Eventually, the number of creatures must also increase since it will be impossible for them to avoid gaining enough energy to divide.
There is one other stable population - the most stable situation - when there are no creatures. Once the world reaches this state, the number of creatures can never change (though the amount of food will increase forever).
If we look at the population size over time, we can see that the number of creatures does seems to oscillate around 50 creatures, with a mean of 56 over the period I recorded.
Stable food amount
Now we know the system is stable with 50 creatures, we can figure out how much food is stable. Food is created, on average, every 10 ticks, so in a stable system, one food will be eaten every 10 ticks.
Creatures have a radius of 3 pixels, and each food has a radius of 1 pixel. So food within 4 pixels either side of a creature's position gets eaten. This means as creatures move, they sweep out a line of 8 pixels. Over the course of 10 ticks, creatures move 2 pixels, so cover an area of 16 square pixels. Fifty creatures therefore cover 800 square pixels in the time in takes for one food to appear. This is $\dfrac{1}{300}$ of the 400 x 600 world area, which I think means we need 300 food in the world in order that creatures eat an average of 1 every 10 ticks. That looks about right on the graph and the mean for period I recorded was 312.
This gives a formula for the average amount of food:
- $A_{world}$: Area of the world
- $R_{food}$: Rate of food production
- $r_{creature}$: Radius of creatures
- $r_{food}$: Radius of food
- $n$: Mean number of creatures
- $s$: Speed of creatures
I made a few simplifications for this calculation. Firstly, it's possible for food to be created on a creature, which means it will be eaten immediately. The probability of this happening is about 1%. It is also possible that creatures will change course over 10 ticks, reducing the area they cover, and creatures and their paths can overlap, reducing the area further. This is fairly unlikely over 10 ticks, but will slightly increase the amount of food required.
How stable is stable?
I've been talking about the number of food and creatures that are stable. But what actually happens when we start with 50 creatures and 300 food? Does the world continue unchanging forever?
It turns out, that although there is a stable point that the populations oscillate around, they don't stay there. Starting with 50 creatures and 300 food avoids the wild swings at the beginning of the simulation, but there are still some fairly large peaks and crashes later on.
Something I'm interested in looking into is what influences the time between cycles and how large the peaks and troughs are. From the graph it appears that the cycle length is slightly more than 2 minutes (6000 ticks). I suspect both properties are related to how quickly the creatures respond to a change in food amount.
In a large world (or with slower creatures, which effectively makes the world larger for them) the environment can be more heterogenous, with some areas having more food and fewer creatures, with other areas having the reverse, smoothing out the peaks and troughs. A smaller world will mean an excess of creatures will quickly eat the food and starve. When I get a chance I'll experiment with changing various parameters.
Implementation details
There are a few subtle issues with how I've made this simulation, which I think are worth mentioning in case anyone wants to build their own.
Creature order matters
The way I've coded the simulation, food is generated at the beginning of the tick. Then one-by-one each creature moves, eats and reproduces. This means that a creature could move to a piece of food and eat it, then a second creature could move where that food was and miss out. A more correct way to implement this would be to work out which creature reaches the food first, and have that creature take the food.
In this case, I don't think it's too important, and the situation is going to be relatively rare. Since new creatures are added to the end of the array, the creatures will be in age order, so this gives older creatures an advantage which we could imagine as is experience. However, there are some cases where this sort of first-mover advantage is important and can bias your results. One simple solution would be to randomise the order of the creature array each turn so creatures don't have a consist advantage.
Creatures swim through food
The simulation is a discrete time simulation, so we check whether creatures overlap with food in one tick, then update their positions by some amount in the next tick and check again. This represents the creature moving through space during that time period, but it's possible that it will miss the food check, especially if it moves a long way.
If a creature moves fast enough it could move through a piece of food directly in front of it. Currently creatures move 0.2 pixels per tick so it's unlikely they will miss food, but it's worth being aware of if we want faster creatures. If we were making an accurate physics simulation of colliding particles it would be worth fixing, but here it just means creatures have a slightly smaller chance of getting food than you might expect.
Edge effects
If creatures move off the left side of the world they will appear on the right side of the world as though the world were toroidal. However, when calculating the distance between creatures and food, I do a straight calculation of distance between their coordinates in the world. This means that a creature on the extreme edge of the world should overlap with food on opposite side, but it won't until its centre crosses to the next side. I also don't display half a creature on each side, so creatures will suddenly disappear and reappear when their centre crosses an edge.
The reason for this issue basically comes down to laziness and the fact that it doesn't seem worth fixing. In later simulations I will probably remove the wrapping effect and instead have creatures collide with the edges.
Still to do
- Add sliders to control parameters
- Experiment with slower creatures and larger world
- Experiment food with less energy generated more frequently
Comments (1)
Roberto Mior on 3 Nov 2020, 7:12 p.m.
Hi, I too, time ago dedicated myself to the simulation of creaures that evolve in a small ecosystem.
https://miorsoft.itch.io/ecosystem-evolution
I don't want to disturb but maybe this simulation might interest you.
It is a small portable program for Windows.
Regards.