/**
* 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)