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));
    }
 
}