Ant pheromones behavior
for information about this please have a look at The Swarm
Simulation of pheromone behavior
For our Mini-Project in class we tried to create an simulation of ants finding their way from the ant hill to the food and back.
Teaser
Links
Implementation
This is code written with the help of the Processing Framework. Images and the font file are not included. (The latter can be created with processing.)
Version as of 2007-Nov-01. Licensed under the WTFPL
// ANTphetamine // A simulation of ants finding shortest paths by using pheromones // (C) 2007 Felix Faulmann, Daniel Rentzsch & Thomas Efer // Part of the lecture "Nature Inspired Computing" /////////////////////////////////// SETTINGS & GLOBAL VARS ////////////////////////////////////////////////////// // SETTINGS: /////////////////// int maxAntNum = 1000; // Maximum Ant number int antNum = 0; // count variable Ant[] ants; // Array where ant-Objects are stored int dimx = 800; // Window width int dimy = 600; // Window heigth int homex = 180; // Home location X int homey = 200; // Home location Y int homerad = 20; // Home radius int foodx = 630; // Food location X int foody = 330; // Food location Y int foodrad = 25; // Food radius float[][] searchmap; // Map where the "Searching for food"-pheromone is stored float[][] foundmap; // Map where the "Searching for home"-pheromone is stored PImage bgimg; // Background image PImage himg; // PImage fimg; boolean drawProgress=true; // Switch display of ants and pheromone trails int sweepc=0; // Counter that controls the removal of pheromones from the map int sweepsteps = 10; // Reduce the pheromone density each [n] simulation steps float redfact = .996; // Factor of pheromone reduction per simulaton step float redval = .04; // Additional absolute value of pheromone reduction per simulaton step int foodScore; // statistical counter int homeScore; // statistical counter float pinc=10; // pheromone drop ammount per ant int birthrate = 5; // influences the number of ants born in one simulation step (see coded formula below) float divAng = PI*6/21; // Angle difference (left & right) to check pheromone density (2 steps ahead) float gainAng = PI*6/17; // Angle to turn into best direction each step int dcprob = 85; // Probability (in %) that the direction is changed in a particular simulation step float randdiff = PI/18; // Random direction change bias maximum (into each direction) float threshold = 120; // Pheromone ammount maximum where direction changes (dizziness threshold) /////////////////////////////////// INITIAL SETUP //////////////////////////////////////////////////////// void setup () { size(dimx,dimy,P3D); // Set window size ants = new Ant[maxAntNum]; // Initialize ant array searchmap = new float[dimx+1][dimy+1]; // Initialize maps foundmap = new float[dimx+1][dimy+1]; // textFont(loadFont("LucidaSans-Italic-16.vlw")); // Load bitmap font bgimg = loadImage("bg.jpg"); // Load background image himg = loadImage("home.png"); // Load home image fimg = loadImage("burger.png"); // Load food image // create initially scattered ants for (int i= 0; i < maxAntNum/20; i++) ants[antNum++]=new Ant(true); } /////////////////////////////////// DRAW CYCLE (Also main simulation step) ///////////////////////////////////////////////// void draw() { // Buffering on loadPixels(); // Draw the Background background(bgimg); // Pheromone drawing and reduction sweepc=sweepc++%sweepsteps; for(int i=0; i<height; i++) { for(int j=0; j<width; j++) { // Draw the pheromones when necessary float s=searchmap[j][i]; float f=foundmap[j][i]; if (s>0 || f>0) { if (drawProgress) pixels[i*width + j] = color(red(bgimg.pixels[i*width + j])+s*2,+green(bgimg.pixels[i*width + j]),blue(bgimg.pixels[i*width + j])+f*2); } // in sweep-simulation-steps, reduce the pheromone ammount if (sweepc == 0) { searchmap[j][i]*=redfact; foundmap[j][i]*=redfact; searchmap[j][i]-=redval; foundmap[j][i]-=redval; if (s<0) searchmap[j][i]=0; if (f<0) foundmap[j][i]=0; } } } // Draw home and food images where they belong image(himg, homex-homerad,homey-homerad); image(fimg, foodx-foodrad,foody-foodrad); // Move and draw the ants (call each ant's move method and (if needed) their paint method) for (int i = 0; i < antNum; i++) {ants[i].move(); if (drawProgress) ants[i].paint();}; // output statistics fill(0,0,0,180); text("Ant count: "+antNum+" | Food sightings: "+foodScore+" | Safe returns: "+homeScore, 15, 30); fill(255,255,255); text("Ant count: "+antNum+" | Food sightings: "+foodScore+" | Safe returns: "+homeScore, 14, 29); // Buffering off (bake image to screen) updatePixels(); // New ants to be born? if (antNum < maxAntNum) for(int i = 0; i< (maxAntNum-antNum) * birthrate / maxAntNum +1; i++) ants[antNum++]=new Ant(); } /////////////////////////////////// EVENT HANDLERS /////////////////////////////////////////////////////////// // On any key pressed switch display mode (full / counters only) void keyPressed() { drawProgress=!drawProgress; } // On mouse dragging paint fat pheromone trail (debug) void mouseDragged() { addFoundPher((int)mouseX,(int)mouseY,100); addSearchPher((int)mouseX,(int)mouseY,100); addFoundPher((int)mouseX+1,(int)mouseY+2,10.0); addSearchPher((int)mouseX-1,(int)mouseY-2,10.0); addFoundPher((int)mouseX-2,(int)mouseY+1,10.0); addSearchPher((int)mouseX+2,(int)mouseY-1,10.0); } /////////////////////////////////// HELPER FUNCTIONS /////////////////////////////////////////////////////////// void addSearchPher(int x, int y, float pher) { searchmap[(int)x][(int)y]+=pher; searchmap[(int)x][(int)y+1]+=pher/2; searchmap[(int)x][(int)y-1]+=pher/2; searchmap[(int)x+1][(int)y]+=pher/2; searchmap[(int)x-1][(int)y]+=pher/2; } void addFoundPher(int x, int y, float pher) { foundmap[(int)x][(int)y]+=pher; foundmap[(int)x][(int)y+1]+=pher/2; foundmap[(int)x][(int)y-1]+=pher/2; foundmap[(int)x+1][(int)y]+=pher/2; foundmap[(int)x-1][(int)y]+=pher/2; } /////////////////////////////////// ANT CLASS ///////////////////////////////////////////////////////////// // Represents a single Ant class Ant { // fields float x; float y; float dir; boolean foodsearch = true; // Constructor for birth placement near home Ant(){ x=homex+random(-homerad,homerad)*.7; y=homey+random(-homerad,homerad)*.7; dir=random(0,2*PI); } // Constructor for randomly scattered birth (debug) Ant(boolean randomizer){ x=random(4,dimx-4); y=random(4,dimy-4); dir=random(0,2*PI); } // void move() { // helper variables float xold = x; float yold = y; x=x+sin(dir); y=y+cos(dir); // Hit the border of the Universe? Try turning around somewhat randomly. if ((x < 2) || (y < 2) || (x >= dimx-1) || (y >= dimy-1)) {dir=(dir+3*PI)%(2*PI)+random(-PI/2,PI/2); x = xold; y = yold;}; // Move this time? if(random(0,100)<dcprob) { // Have some random divergence float DIFF = random(-randdiff,randdiff); // Take 3 pheromone probes (bad but performant estimation of ant's real pheromone perception) float leftVal; float straightVal; float rightVal; // Take it from the found-food-map when searching food if (foodsearch) { leftVal = foundmap[(int)(x+2*sin(dir+divAng))][(int)(y+2*cos(dir+divAng))]; straightVal = foundmap[(int)(x+2*sin(dir))][(int)(y+2*cos(dir))]; rightVal = foundmap[(int)(x+2*sin(dir-divAng))][(int)(y+2*cos(dir-divAng))]; } // Et vice versa else { leftVal = searchmap[(int)(x+2*sin(dir+divAng))][(int)(y+2*cos(dir+divAng))]; straightVal = searchmap[(int)(x+2*sin(dir))][(int)(y+2*cos(dir))]; rightVal = searchmap[(int)(x+2*sin(dir-divAng))][(int)(y+2*cos(dir-divAng))]; } // Decide for the better one if (leftVal > straightVal && leftVal > rightVal) DIFF+=gainAng; if (rightVal > straightVal && rightVal > leftVal) DIFF-=gainAng; // Take into consideration that ants freak out (or just walk on stupidly) when there's too much pheromone in their way. if (straightVal > threshold) DIFF=0; //DIFF+=random(-2*PI,2*PI); // // Have some additional random divergence (useless? maybe!) DIFF += random(-randdiff/5,randdiff/5); // And finally set the new direction value dir=(dir+DIFF+2*PI)%(2*PI); } // Destiny reached? Turn around and do the oppsite thing! Increase the fitting counter by the way... if (foodsearch && sqrt((foodx-x)*(foodx-x)+(foody-y)*(foody-y)) < foodrad) {dir=(dir+3*PI)%(2*PI); foodsearch=false; foodScore++;} if (!foodsearch && sqrt((homex-x)*(homex-x)+(homey-y)*(homey-y)) < homerad) {dir=(dir+3*PI)%(2*PI); foodsearch=true; homeScore++;} // And don't forget to "deposit" pheromones if (foodsearch) addSearchPher((int)x,(int)y,pinc); else addFoundPher((int)x,(int)y,pinc); } // Draw each individual ant void paint() { stroke(0,0,0); //point(x,y); ellipse(x-1,y-1,2,2); stroke(255,255,255); point(x+sin(dir),y+cos(dir)); } }
