We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi everyone, i'd like to share with you the project i'm working on. First of all i want to give credit to Daniel Shiffman form "the coding train", i started learning Processing just a month ago, and i heavily relied on his amazing work.
This is an ecosystem simulation in which creatures can evolve from generation to generation based on their previous performances. There are 2 main classes of creatures, herbivores (Bloops = black/pink circles) and carnivores (Predators = brown/red triangles). Each species implements steering behavior such as seek and flee based on their own senses.
they carry a dna that initialize their stats like hearing range, max health, and so on. When two creatures mate, the dna is taken from the parents and mixed to generate a child that will carry his parents genes. To avoid evolution to strive just for maximizing stats, every value is inversely proportional to another one (eg. hearing is initialized by gene[0], smell is equal to the maximum possible hearing value - hearing, so if you have incredibly developed hears, you'll end up with almost no sense of smell and vice versa). That way evolution will have to find a good balance between stats over time. After reaching the mating age, every creature can emit hormones to attract possible partners. if the ecosystem collapse (less than 2 creatures left per species) it resets, evaluate every creatures based on age and child number, randomly choose among creatures (higher evaluation = higher chance of being chosen), cross their genes, and generates a new ecosystem populated with the newborn children.
I tried to comment the code as much as possible to make it readable. This is unfinished but still fun to watch. Right click to show/hide the thinking process of the creatures. Click on a creature to show/hide its senses.
World world;
boolean thinkingProcess = true;
int generations;
int lifetime;
int numF;
int numB;
int numP;
float mutationRate;
float bestBloop;
float bestPredator;
int longestGeneration;
int bloopScore;
int predatorScore;
void setup() {
fullScreen();
numF = 200; // initialize food count
numB = 50; // initialize bloops population
numP = 30; // initialize predators population
mutationRate = 0.01; // set mutationRate
bestBloop = 0;
bestPredator = 0;
lifetime = 0;
generations = 0;
longestGeneration = 0;
bloopScore = 0;
predatorScore = 0;
world = new World(numF, numB, numP);
}
void draw() {
background(255);
// run simulation until there are at least 2 predators and 2 bloops (if one of the species goes up to 200+ units, something went wrong, so reset ecosystem)
if ((world.predators.size() > 1) && (world.bloops.size() > 1) && (world.predators.size() < 200) && (world.bloops.size() < 200)) {
world.run();
lifetime++;
} else {
if (world.bloops.size() > world.predators.size()) { // check which species survived
bloopScore += 1;
} else {
predatorScore += 1;
}
for (int i = world.bloops.size()-1; i >= 0; i--) { // check for surviving bloops
Bloop b = world.bloops.get(i);
b.age += b.health; // reward them by adding exceeding health to fitness
world.bloopsClones.add(b); // move them to the clones arraylist
world.bloops.remove(i); // remove them from bloop arraylist
}
for (int i = world.predators.size()-1; i >= 0; i--) { // do the same for predators
Predator p = world.predators.get(i);
p.age += p.health;
world.predatorsClones.add(p);
world.predators.remove(i);
}
if (lifetime > longestGeneration) longestGeneration = lifetime;
lifetime = 0; // create new generation
generations++;
world.pFoods.clear();
world.foods.clear(); //clear old food array
for (int i=0; i < numF; i++) {
world.foods.add(new Food(random(0, width), random(0, height))); //initialize food for the next gen
}
world.getBloopsMaxFitness(); // calculate bloops fitness
if (world.getBloopsMaxFitness() > bestBloop) {
bestBloop = world.getBloopsMaxFitness();
}
world.bloopSelection(); // select bloops
world.bloopReproduction(); // reproduce bloops
world.getPredatorsMaxFitness(); // calculate predators fitness
if (world.getPredatorsMaxFitness() > bestPredator) {
bestPredator = world.getPredatorsMaxFitness();
}
world.predatorSelection(); // select predators
world.predatorsReproduction(); // reproduce predators
}
fill(0); // display some stats
textSize(12);
text("Generation #: " + (generations), 10, 18);
text("Lifetime: " + (lifetime), 10, 36);
text("Living Bloops: " + world.bloops.size(), 10, 54);
text("Living Predators: " + world.predators.size(), 10, 72);
text("Oldest Bloop: " + bestBloop, 10, 90);
text("Oldest Predator: " + bestPredator, 10, 108);
text("Longest generation: " + longestGeneration, 10, 126);
text("Bloop score: " + bloopScore, 10, 144);
text("Predator score: " + predatorScore, 10, 162);
text("Click on a creature to display senses", width-250, height-33);
text("Right click to toggle thinking process", width-250, height-15);
}
void mousePressed() { // show/hide creatures thinking process
if (mouseButton == RIGHT) {
thinkingProcess = !thinkingProcess;
}
if (mouseButton == LEFT) {
for (int i = 0; i < world.bloops.size(); i++) { // show/hide creature senses when you click on it (red circle = hearing, green = smell)
world.bloops.get(i);
if (mouseX > world.bloops.get(i).position.x - world.bloops.get(i).r*2 && mouseX < world.bloops.get(i).position.x + world.bloops.get(i).r*2 && mouseY > world.bloops.get(i).position.y - world.bloops.get(i).r*2 && mouseY < world.bloops.get(i).position.y + world.bloops.get(i).r*2) {
world.bloops.get(i).showSenses = !world.bloops.get(i).showSenses;
}
}
for (int i = 0; i < world.predators.size(); i++) {
world.predators.get(i);
if (mouseX > world.predators.get(i).position.x - world.predators.get(i).r*4 && mouseX < world.predators.get(i).position.x + world.predators.get(i).r*4 && mouseY > world.predators.get(i).position.y - world.predators.get(i).r*4 && mouseY < world.predators.get(i).position.y + world.predators.get(i).r*4) {
world.predators.get(i).showSenses = !world.predators.get(i).showSenses;
}
}
}
}
Comments
Hope everything works fine, there's still a lot to do but it's quite fun to watch. you can tune parameters and see what changes in the evolution of the creatures.
If you like the project i'll keep you updated!!!
enjoy :D
Very impressive work
Thanks for sharing
You could upload it on github
Best, Chrisir
Hello @m4l4. Here Venerando, from Spain. Im very interested in the matter of genetic algoritms and also arrived into Processing after reading the book "The nature of code" by Daniel Shiffman, a very interesting book. I am implied now in developing a database manager for Processing, as I would like to develop a genetic program that stores the evolution of an ecosystem like yours. I expected to have finished before, but it is proving to be more complicated than I thought. However, I have learned a lot from it and hope to finish soon. Then I'll start doing my genetic project. Surely I will copy things from yours. Anyway, if you want to have a look at my database manager, you can do it at https://github.com/vesolba/DBManager-for-Processing
Greetings.
hi @vesolba, feel free to copy whatever you want (as i did myself ;P) i'm not a programmer nor an engineer, just a geek with a lot of patience ;P I like your idea and i was thinking about something like that for the next part of my project, i want to add a neural network to the simulation (a lot easier to say than it actually is) and i will need a way to "save" the brain of the creatures whenever i quit the simulation. I'm struggling to write a rnn lstm in processing, i'll post something as soon as i have something that actually works.