/**
* Name:  Movement on a Grid of Cells
* Author:  Patrick Taillandier
* Description: Model to represent how the agents move from one point to a target agent on a grid of cells with obstacles, following the shortest path and coloring 
* 	in magenta the cells intersecting the path of an agent
* Tags: grid, agent_movement, skill, obstacle, shortest_path
*/

model Grid

global {
	/*2 algorithms for the shortest path computation on a grid with weights:
	*      - A* : default algorithm: An introduction to A*: http://www.redblobgames.com/pathfinding/a-star/introduction.html
	*      - Dijkstra : Classic Dijkstra algorithm. An introduction to Dijkstra : http://www.redblobgames.com/pathfinding/a-star/introduction.html
	*/
	
	file dem <- file("../includes/vulcano_50.asc");
	geometry shape <- envelope(dem);
	string algorithm <- "A*" among: ["A*", "Dijkstra"] parameter: true;
	int neighborhood_type <- 8 among:[4,8] parameter: true;
	map cell_weights;

	init {    
		ask cell {grid_value <- grid_value * 5;}  
		float max_val <- cell max_of (each.grid_value);
		ask cell {
			float val <- 255 * (1 - grid_value / max_val);
			color <- rgb(val, val,val);
		}
		cell_weights <- cell as_map (each::each.grid_value);
		create goal{
			location <- (one_of (cell where not each.is_obstacle)).location;
		}
		create people number: 10 {
			target <- one_of (goal);
			location <-  (one_of (cell where not each.is_obstacle)).location;
		}
	} 
}

grid cell file: dem neighbors: neighborhood_type optimizer: algorithm {
	bool is_obstacle <- flip(0.2);
	rgb color <- is_obstacle ? #black : #white;
} 
	 
species goal {
	aspect default { 
		draw circle(0.5) color: #red;
	}
}  
	
	  
species people skills: [moving] {
	goal target;
	float speed <- 1.0;
	aspect default {
		draw circle(0.5) color: #green;
		if (current_path != nil) {
			draw current_path.shape color: #red;
		}
	}
	
	reflex move when: location != target{
		//We restrain the movements of the agents only at the grid of cells that are not obstacle using the on facet of the goto operator and we return the path
		//followed by the agent
		//the recompute_path is used to precise that we do not need to recompute the shortest path at each movement (gain of computation time): the obtsacles on the grid never change.
		do goto (on:cell_weights, target:target, speed:speed, recompute_path: false);
		
		//As a side note, it is also possible to use the path_between operator and follow action with a grid
		//Add a my_path attribute of type path to the people species
		//if my_path = nil {my_path <- path_between((cell where not each.is_obstacle), location, target);}
		//do follow (path: my_path);
	}
}

experiment goto_grid type: gui {
	output {
		display objects_display {
			grid cell border: #black;
			species goal aspect: default ;
			species people aspect: default ;
		}
	}
}