/**
* Name: Ant Foraging (Charts examples)
* Author: Philippe Caillou
* Description: How ants search food and use pheromons to return to their nest once they find it.
* Tags: gui, skill, chart, grid, diffusion
*/
model ants
global {
//Number of ants
int ants_number <- 100 min: 1 max: 2000 ;
//Evaporation value per cycle for the pheromons
float evaporation_per_cycle <- 5.0 min: 0.0 max: 240.0 ;
//Diffusion rate for the pheromons
float diffusion_rate <- 1.0 min: 0.0 max: 1.0 ;
//Size of the grid
int gridsize <- 75 ;
//Center of the grid to put the location of the nest
point center const: true <- { (gridsize / 2), (gridsize / 2)} ;
file types const: true <- (pgm_file('../images/environment75x75.pgm')) ;
int food_gathered <- 0 ;
geometry shape <- square(gridsize);
init{
//Ant are placed randomly in the nest
create ant number: ants_number with: [location::any_location_in (ant_grid(center))] ;
}
//Reflex to diffuse the road of pheromon on the grid
reflex diffuse {
diffuse var:road on:ant_grid proportion: diffusion_rate radius:2 propagation: gradient;
}
}
//Grid to discretize space for the food and the nest
grid ant_grid width: gridsize height: gridsize neighbors: 8 use_regular_agents: false {
bool multiagent <- true ;
float road <- 0.0 max:240.0 update: (road<=evaporation_per_cycle) ? 0.0 : road-evaporation_per_cycle;
int type <- int(types at {grid_x,grid_y}) ;
bool isNestLocation <- (self distance_to center) < 4 ;
bool isFoodLocation <- type = 2 ;
rgb color <- isNestLocation ? °violet:((food > 0)? °blue : ((road < 0.001)? rgb ([100,100,100]) : ((road > 2)? °white : ((road > 0.5)? (#grey) : ((road > 0.2)? (#lightgrey) : (#darkgray)))))) update: isNestLocation ? °violet:((food > 0)? °blue : ((road < 0.001)? rgb ([100,100,100]) : ((road > 2)? °white : ((road > 0.5)? (#grey) : ((road > 0.2)? (#lightgray) : (#darkgray)))))) ;
int food <- isFoodLocation ? 5 : 0 ;
int nest const: true <- 300 - int(self distance_to center) ;
}
//Species ant that will move and follow a final state machine
species ant skills: [moving] control: fsm {
float speed <- 2.0 ;
ant_grid place update: ant_grid (location );
bool hasFood <- false ;
reflex diffuse_road when:hasFood=true{
ant_grid(location).road <- ant_grid(location).road + 100.0;
}
//Action to pick food
action pick {
hasFood <- true ;
place.food <- place.food - 1 ;
}
//Action to drop food
action drop {
food_gathered <- food_gathered + 1 ;
hasFood <- false ;
heading <- heading - 180 ;
}
//Action to chose the best place according to the possible food in the neighbour cells
action choose_best_place type: ant_grid {
list list_places <- place.neighbors ;
if (list_places count (each.food > 0)) > 0 {
return (list_places first_with (each.food > 0)) ;
} else {
int min_nest <- (list_places min_of (each.nest)) ;
list_places <- list_places sort ((each.nest = min_nest) ? each.road : 0.0) ;
return last(list_places) ;
}
}
//Initial state of the ant : wander until it finds food or find a road to follow
state wandering initial: true {
do wander amplitude:120.0 ;
transition to: carryingFood when: place.food > 0 {
do pick ;
}
transition to: followingRoad when: place.road > 0.05 ;
}
//State to carry food to the nest once the food is found
state carryingFood {
do goto target: center ;
transition to: wandering when: place.isNestLocation {
do drop ;
}
}
//State to follow a road
state followingRoad {
location <- (choose_best_place()) as point ;
transition to: carryingFood when: place.food > 0 {
do pick ;
}
transition to: wandering when: (place.road < 0.05) ;
}
aspect default {
draw circle(1.0) wireframe: !hasFood color: #orange ;
}
}
experiment "Experiment" type: gui {
//Parameters to play with in the gui
parameter 'Number of ants:' var: ants_number category: 'Model' ;
parameter 'Evaporation of the signal (unit/cycle):' var: evaporation_per_cycle category: 'Model' ;
parameter 'Rate of diffusion of the signal (%/cycle):' var: diffusion_rate category: 'Model' ;
list> nbants<-[[0]];
list statesnames<-["wandering"];
list categnames<-["empty","carry"];
list> nbantsbydist<-[[0]];
list xytestvallist<-[[[1,1],[2,2],[3,3]],[[1,2],[2,1],[3,4]],[[1,3],[2,3],[0,1]],[[1,4],[2,5],[0,0]]];
list> xyval<-[[1,1],[2,1],[3,2]];
//Reflex to update the charts, belonging to the experiment bloc as it will not be used by other experiment which don't have the charts
reflex update_charts
{
nbants<-list>([]);
statesnames<-list([]);
categnames<-["empty","carry"];
nbantsbydist<-list>([]);
loop x over:(world.ant)
{
if !(statesnames contains (x.state))
{
add [(list(ant) count (each.state=x.state and !each.hasFood)),(list(ant) count (each.state=x.state and each.hasFood))] to: nbants;
add (x.state) to:statesnames;
list nl<-list([]);
loop d from:0 to:9
{
add (list(ant) count (each.state=x.state and (((each distance_to center)>gridsize/20*d) and ((each distance_to center)