Programming

As an engineer I was trained in Matlab, but I'm writing in Python now. Check out the Evolution Simulator and Custom Map Maker.

Evolution Simulator (2020)

This Evolution Simulator is born out of curiosity. Is it possible for a "noob" like me to get some sort of feeling for evolution by simulating it?

The simulation starts with a random group of "Blobs". They have some properties that they can give to their children (genes) and they have an internal physical system consisting of nutrients and energy. Blobs have the following "genes" or values that they pass on to their children (with some change of mutation):

  • Species Name: a random string consisting of five letters. The first, third and fifth letters are consonants, while the second and fourth letters are vowels. A blob recognizes a blob with the same name as its own kind. However, for each consonant there is a probability that it changes, meaning a new species is born.
  • Maximum Size: the maximum diameter of the blob to which it can grow.
  • Baby Size: the initial size of "babies" of the blob.
  • Speed: the fixed speed (velocity magnitude) of the blob when it is moving.
  • Max Growth Rate: the maximum body growth rate of the blob. The actual growth rate may also be limited by available nutrients and energy.
  • Fear: scalar that determines how much the blob is accelerating away from enemies.
  • Hunting: scalar that determines how much the blob is accelerating towards potential food.
  • Photosynthesis: boolean value determining if sunlight gives energy to the blob or not. Note that there is a penalty for photosynthesis: it increases the energy required to move around.
  • Food Size Matters: boolean value determining if the size of potential food is considered in calculating the pull towards it.
  • Enemy Size Matters: boolean value determining if the size of an enemy is considered in calculating the push away from it.
  • Maximum Age: the maximum age in seconds of simulation time. If the blob did not die before, it will die at its maximum age to make room for a new generation.
  • Sleep At Night: boolean value indicating if the blob stops moving at "night"
  • Sleep At Night: boolean value indicating if the blob stops moving at "day"

When the simulation runs, each blob B is subjected to the following algorithm. The settings may change but the idea remains the same.

  1. B is pulled towards potential food. All other blobs within a certain "sphere of influence" that are smaller than 90% of B itself are considered potential food. An acceleration vector towards each potential food blob is generated. The acceleration depends on the proximity of the potential food and the Hunting gene. If B has the gene Food Size Matters enabled, the potential food size is also considered in the equation as a scalar.
  2. B is pushed away from potential enemies. All other blobs within the sphere of influence that are larger than B itself are considered potential enemies. The acceleration away depends on the proximity of the potential enemy and the Fear gene. If B has the gene Enemy Size Matters enabled, the potential enemy size is also considered in the equation as a scalar. Additionally, the edge of the simulation area is also considered as extra push factor, to avoid blobs moving away to infinity.
  3. The resulting acceleration of B is calculated and its new velocity determined. Acceleration is the sum of all food pull vectors, enemy push vectors and the area-edge push vector. Acceleration decreases with increasing mass, so larger blobs have a harder time changing course. The final velocity is always scaled to equal the genetically stored Speed. In other words: only the course of the blob changes.
  4. The blob burns energy for moving. If the blob moves, energy is removed based on the speed (linear scaling) and size (quadratic scaling). If the blob does not move because it has the gene(s) Sleep At Night or Sleep at Day enabled, no energy is withdrawn. Important penalty: when the Photosynthesis gene is active, moving costs 30 times more energy! This sounds like a lot, but still photosynthesis genes dominate the simulations because they are the only ones to withdraw energy from sunlight. In any case, when the blob has moved, energy is withdrawn from the active energy level. If this is insufficient, energy is withdrawn from the stored body energy (starvation response) to keep moving. If moving has resulted in a total energy level below some given minimum, B will die after this step.
  5. Collisions with other blobs are handled. If a collision is detected, the following can happen:
    • Our blob B is eating the other blob if that other blob is of a different species and smaller than 90% of B's size. The other blob is removed from the game and 80% of its energy and 100% of its nutritients are transferred to B so it may grow and move and get babies.
    • B is eaten by the other blob and the reverse happens.
    • If the other blob is nearly the same size as B and/or it has the same Species Name, it bumps into it and reverses its velocity. Depending on simulation settings, this may come at the penalty of some energy loss (Bumping hurts, you know. We want to avoid that).
  6. Our blob may die. When the total energy level of B drops below a certain threshold, it will die and be removed from the simulation. Energy is removed by moving, being eaten or by old age. Growing does not remove energy, but converts active to potential energy.
  7. Before growth is calculated, the blob will receive energy from sunlight if it has the Photosynthesis gene. The energy from sunlight scales quadratically with the diameter of the blob. Photosynthesis gives active energy, but only during simulated "daytime". The downside for photosynthesis is a huge energy penalty for moving.
  8. If still alive, B grows. Firstly, growth needs energy (active energy, not stored as body mass). Each simulated second, a small fraction of active energy can be used to grow. If growing, the active energy is stored as chemical energy in the body of the blob. The stored energy scales with the mass of the blob and vice versa. Secondly, to grow, nutritients are required. At each position in the simulated world, some nutritients are initially available. Based on the surface area of B, it can absorb these nutritients. Once absorbed, they are "active nutritients". A certain fraction of these is used to grow. When B dies, all its stored nutritients are returned to the world at the spot where it died. The game "smoothens" the nutritient field over time to simulate the spreading of elements in e.g. soil. Blob growth can be limited by either available active energy, available active nutritients, or the limit stored in the gene Max Growth Rate.
  9. After changing course, moving, colliding, eating, not dying and growing, our blob B may get babies. Babies are produced when B meets the following conditions:
    1. A certain time has passed since the last "nest" of babies of B was born. The minimum time between a new "nest" of babies equals (1 + 10 * Baby Size) seconds. So a gene for larger babies means a longer repoduction time is required.
    2. The baby's initial energy is removed from the parent during "birth". The parent blob B has at least 3 times more energy (stored + active) than what must be given to the baby. The energy initially given to the baby depends on the gene Baby Size and a fixed minimum active energy.
    3. The active nutritients available for the baby must be sufficient to give it its initial size and a fixed starting level of active nutritients.
    So, when B gets a baby, it loses energy and nutritients. Per "nest", multiple babies may be generated when the energy and nutritient conditions allow this. Then, the internal "baby timer" is reset. The procedure repeats when all conditions are met again.
    Each baby inherits its "genes" from its parent, but there is a probability of a few percent per gene that it may change value by some random number.
  10. This procedure is repeated for each individual blob B in each timestep. Blobs with photosynthesis are greenish, the others are more red and purple. As shown in the video, different species dominate for a while before they give up their position in the ecosystem to a new species.

With the genes and rules described above, the system is quasi-stable: most of the simulations go on for a very long time until I have to shut down the computer, but some of them are unstable and die out with bad luck.

I have found that many strategies exist for the blobs to survive and that they depend on the ecosystem as a whole. There is not a single "good" strategy for the blobs, as the circumstances may change quickly. Rapidly growing food may die from over-population (bumping into each other), leaving hunters with nothing to eat. Species that were food before may now have evoluted into larger individuals that can be hunted. Or babies have a small genetic difference that makes them more speedy, depleting them of energy too quickly. If green blobs move at night they lose energy they get from photosynthesis during the day. So sleeping is an option, although night-hunters may appear that rapidly eat all the green blobs at night and produce many babies. There is a lot more to tell about this simulator! You can always e-mail me with questions.

Back to top

The V0.1 Blob evolution simulator at 100x speed. Notice the balance of species is continuously changing.

The V0.2 Blob evolution simulator at 80x speed. The RGB color of each blob depends on its genes. Higher red values indicate higher "hunting". Higher blue values indicate higher "fear" and green values indicate if the blob uses photosynthesis. As you see, green blobs make out the majority of the population.

Custom Map Maker

You may know those websites that let you order a print of a customized map to decorate your walls. I wanted to have something like that, but in my own control. For Flying Fish, I wrote a Python script that uses the Google static maps API to create maps in the Flying Fish color scheme. With Matplotlib, the "map tiles" are made overlapping to achieve a higher resolution than possible with the API alone. Canvas prints of many water-rich cities now embellish the walls of our office, sponsored by team members. All maps are on the same scale for comparison. In my opinion, especially the map of Seattle looks very artistic this way.

Back to top

Amsterdam
Rotterdam
Seattle
Amsterdam
All map data © Google