A silly project I made in 2015/2016 (I think) in a state of perpeutal panic for the course “Theoretical Modelling in Biology (B-KUL-G0G41A)” at KU Leuven. The code and documentation is preserved here in all its frantic glory (entirely out of nostalgia).
For the purpose of actual science (studying the evolution of flocking) it’s not a very good or realistic simulation. But it sure as hell was fun to code up in two-and-a-half months. Up to that point my Python code was mostly crappy bioinformatics scripts and simple crappy web apps – this, on the other hand, was my first real crappy Python program.
I should probably mention here that the quality of my Python code has improved since I finished this back in early 2016 :x
The script implements a flock of Boids and a PredatorBoid (or two) to hunt them. The Boids are hunted down and eaten one by one by the PredatorBoids, until a user-defined number of Boids has been eaten, whereupon the remaining number of boids get to breed a new generation of a flock and the simulation restarts.
If I remember correctly, the boids should have a simple genetic code that determines how strongly they adhere to any of the rules of the flocking behavior. This code can mutate, and so on.
There’s a GUI, implemented through pygame, where the user can watch them die and evolve. Pretty grisly, huh?
- Python 3.11
- pygame 2.6.1
Create an environment with micromamba:
micromamba create -n flockingboids -c conda-forge python=3.11 pygameRun the simulation from this directory:
micromamba run -n flockingboids python run.pyPress H to toggle headless mode, R to show detection radii, or V to show velocity vectors. Close the window to stop. The simulation writes TSV data files to the current directory.
Boids sense flockmates and predators only within their forward vision cone. Predators likewise pursue prey only within their own vision cone. Adjust fov and perceptionRadius for boids, or predatorFov and predatorPerceptionRadius for predators, in run.py. Set a field of view to 360 degrees for all-around vision. Press R to show the cone outlines along with the minimum-distance circles.
For a finite run without a window, use:
micromamba run -n flockingboids python run.py --headless --max-generations 2--max-steps N stops after N simulation steps, which is useful for quick checks.
Starting colors are randomized per boid and inherited by later generations. The maxInitialColorGeneValues setting in run.py controls their starting range independently of maxInitialGeneValues, which remains at zero for flocking behavior. The phenotype metrics record red, green, and blue gene values; the displayed RGB channels are those values multiplied by 50 and limited to 255.
Each run writes six tab-separated files with the same timestamp and simulation ID prefix:
*_phenotypes.tsvand*_genotypes.tsvrecord newborn genes in generation 0 and everyprintPerNthGengenerations thereafter. Genotypes have two rows per boid, one for each chromosome.*_order.tsvrecords flock alignment everyprintOrderPerNthTickticks in those sampled generations.*_metadata.tsvrecords a format version, UTC start time, and the simulation settings used for the run.*_fates.tsvhas one row per boid in every generation.boid_idand parent IDs usegeneration:local_id. Theoutcomeissurvived,predation,collision, orcensored;death_tickis the one-based step number for deaths.Censoredmeans the run ended before that boid’s generation completed.*_generations.tsvrecords the exact number of ticks, births, deaths by cause, and boids alive at the end of each generation.statusiscompletewhen the kill threshold was reached,stoppedfor a clean early stop, orextinctwhen fewer than two boids remain.
The fate file includes phenotype values for both survivors and casualties, so their genes can be compared within a generation. Old .txt runs keep their original format; their missing death and parent information cannot be reconstructed.
Run the test suite with:
micromamba run -n flockingboids python -m unittest discover -s tests -v