Modeling a Population and Food Consumption


This article will describe how primsoup models the interaction between a breeding population of creatures and their food supply.

Concept

I was interested in seeing if I could replicate the natural patterns of a population of animals and their food supply. In my limited understanding, predator and prey populations have a dramatic impact on each other.

When a prey population is low, predators have a hard time finding prey. This causes starvation and reduces number of healthy offspring that the predators can raise. Starvation and reductions in offspring will drive the predator population down.

When the predator population is low, prey have an easy time moving about to find food and mates. Well-fed and easy-breeding prey quickly increase their numbers with large litters and a high survival rates. As the prey population increases, predators have an easier time finding food and keeping their young healthy. This increases the predator numbers and the cycle repeats.

For the first iteration, I decided to simplify the simulation. I would simulate herbivores eating immobile plants instead of predators chasing prey.

Constraints

The first step was creating constraints on the creatures. These were the constraints I settled on:

  • Speed
  • Hunger
  • Mates and Gestation
  • Vision
  • Age
  • Finite Food Supply

Speed

Each creature has a speed attribute. That attribute dictates how much they can move over time. The world simulation would tell each creature how much time had passed, and the creature would move according to their speed and the time elapsed.

This is a powerful constraint because it prevents creatures from instantly reaching a distant food source when they are hungry. It also means that there is competition between creatures to get to a desired food item first.

Hunger

Over time, the simulated creatures would become more hungry. A creature's hunger is not a binary attribute. Effectively, a creature has a hunger value between 1 and 10. As time passes, it increases to 10 - at which point a creature seeks food no matter what. When a creature eats, the hunger value is decreased based on how much food it found. If the creature finds only a small plant, its hunger may decrease only a small amount. This had two main impacts on the creatures.

First, hunger controlled a creature's behavior. If a creature was not hungry (it just ate), that creature would not aggressively seek out food. It is satisfied and would prefer to wander around or look for mates. Eventually, the hunger starts to rise again. As it does, the creature becomes more concerned with finding food.

Secondly, hunger can lead to death by starvation. If a creature fails to find food before its hunger exceeds the starvation threshold, it will die. This is a very powerful constraint because it is the primary cause of death for the creatures in the simulation.

Finite Food Supply

The primsoup world does not attempt to simulate realistic plants. New plants are periodically generated and placed at a random position in the world.

Plants have a size attribute that determines how much they can feed a creature. That size increases linearly over time until it hits an upper bound. When a creature feeds on a plant, they reduce the size of the plant by an amount based on the creature's hunger. If the creature is hungry enough to eat the entire plant, that plant is removed from the world.

The rate of new plants being created, and the rate that existing plants grow, is constant.

Vision

The creatures inhabit a simulated world that has other creatures and food items in it. A specific creature is not automatically aware of all the other creatures and food sources. Primsoup simulated a form of vision for each creature.

A creature in primsoup has a position and direction they are facing. That means it can "see" any entities within a semicircle that is in front of the creature. The radius of the semicircle is determined by a sight distance attribute on the creature, its direction is determined by the orientation of the creature.

A creature can remember an entity that it saw even if it goes out of its vision. So if it sees food, but is not hungry enough to eat now (or becomes more interested in a mate), it can try to find that same food item again later.

Age

Age is the other possible cause of death for a creature. Once they obtain a specific age, they have a chance to die. This chance increases as they age beyond this threshold.

Additionally, creatures become sexually mature after a certain age. Before that age, they cannot reproduce. This means that the creatures must avoid starvation long enough to become sexually mature if they are to mate.

Mates and Gestation

The primsoup world requires two creatures of opposite genders to create offspring. This constaint means that a creature must wander until it finds a mate that is the opposite gender and sexually mature.

There is competition between creatures because once a creature becomes pregnant, it can no longer mate. It is beneficial to be the first to reach a mate. Once the gestation period expired, an offspring is produced and the birthing creature can mate again.

The Results

Once the simulation was running, I created an observer application to periodically capture statistics about the world. The raw results can be found here. As you can see, the observer just wrote the statistics to a text file. Then I created a simple graph in Excel.

After fixing an endless stream of bugs, I ended up with some data that looked reasonable. For entertainment, here is a list of bugs that had to be squashed:

  • Creatures did not wander randomly, but always in a general NW direction - Vector math error
  • Creatures attempted to mate with pregnant creatures - Gender check confused with fertility check
  • Creatures were immortal - Age check missing
  • Creatures were zombies - death by old age did not prevent moving and feeding
  • Creatures were insatiable - feeding did not reduce hunger correctly
  • Creatures gave inifinite births - birth function did not clear pregnant flag

Once those issues were dealth with, the data looked like what I had expected (or hoped for). We can see the food supply increasingly linearly. In time ~20, the population is seeded with 10 creatures. Those creatures were placed randomly in the world, so they have a hard time finding each other.

The population barely moves for about 500 ticks. A few new creatures are born, and a few die of old age. The food supply is extremely plentiful, so no creatures die of starvation.

Around time 600 we see the beginning of a population growing exponentially. Mates are becoming easier to find and food is still very plentiful. Laissez les bon temps rouler!

But the good days are numbered. Eventually, the booming population overwhelms the food supply. The available food dives dramatically, while the population hits its apex. We expect the apex of the population to lag the drop in food supply, because the creatures take some time to starve.

The population correction via starvation starts at around 1345. It is a powerful and unforgiving correction. Almost half the population dies in a very short time. Then - over the next 200-300 ticks - the somewhat lucky individuals start to die as well. Food is still very hard to find as the population continues decline to an equilibrium.

Around tick 1700 we see that the population has reached an equilibrium point. The losses have slowed down, and the birth rate is again able to keep the population levels constant. We also see the food supply start to recover. The growth is well below the initial linear rate though. That is because now we have a healthy creature population pursuing life, liberty, and happiness.