ForagerRL_step2 - gama-platform/gama GitHub Wiki
By Killian Trouillet
This second step adds a forager agent that moves randomly on the grid. The forager is displayed as a blue circle and moves one cell per simulation step in a random direction (up, right, down, or left). It cannot walk through obstacles or outside the grid boundaries.
- Definition of the
foragerspecies with amy_cellattribute linking it to the grid - Definition of a
random_movereflex for movement - Display of the forager as a blue circle
- Boundary and obstacle collision checking
We define a new species called forager. The key attribute is my_cell, which stores a reference to the grid cell the forager currently occupies. This links the agent to the grid topology.
species forager {
world_cell my_cell;
-
world_cell my_cell: A variable of typeworld_cell(our grid species). This acts as the forager's "position" on the grid.
A reflex is a behavior that is automatically executed at every simulation step. Here, we pick a random direction (0–3), compute the target coordinates, check boundaries and obstacles, and move.
reflex random_move {
int direction <- rnd(3);
int new_x <- my_cell.grid_x;
int new_y <- my_cell.grid_y;
switch direction {
match 0 { new_y <- new_y - 1; } // up
match 1 { new_x <- new_x + 1; } // right
match 2 { new_y <- new_y + 1; } // down
match 3 { new_x <- new_x - 1; } // left
}
if (new_x >= 0 and new_x < grid_size and new_y >= 0 and new_y < grid_size) {
world_cell target <- world_cell grid_at {new_x, new_y};
if (not target.is_obstacle) {
my_cell <- target;
location <- my_cell.location;
}
}
}
-
rnd(3): Returns a random integer between 0 and 3 (inclusive). -
switch/match: A control structure to execute different code depending on the value. This is cleaner than a chain ofif/else. -
my_cell.grid_x/my_cell.grid_y: Built-in attributes of grid cells giving their column and row indices. -
location <- my_cell.location: Updates the forager's geometric position to the center of the target cell, so it is displayed correctly.
An aspect defines how the agent is displayed.
aspect default {
draw circle(0.8) color: #blue;
}
}
-
draw circle(0.8): Draws a circle with radius 0.8, large enough to be clearly visible within a grid cell. - The
defaultaspect is used automatically when no specific aspect is requested.
In the global init block, we create one forager and place it at position (0, 0):
create forager number: 1 {
my_cell <- world_cell grid_at {0, 0};
location <- my_cell.location;
}
We add the forager species to the display. Order matters: agents drawn later appear on top.
display "Grid World" {
grid world_cell border: #lightgray;
species forager;
graphics "food" {
ask world_cell where each.is_food {
draw circle(5) color: rgb(50, 180, 50);
}
}
}
/**
* Name: SmartForager - Step 2: The Forager Agent
* Author: Killian Trouillet
* Description: This second step adds a forager agent that moves randomly on the grid.
* The forager cannot walk into obstacles or outside the grid boundaries.
* Tags: reinforcement-learning, grid, agent, movement, tutorial
*/
model SmartForager
global {
int grid_size <- 10;
int food_x <- 9;
int food_y <- 9;
list<point> obstacle_positions <- [{2,2}, {3,2}, {2,3}, {6,4}, {7,4}, {7,5}];
init {
ask world_cell grid_at {food_x, food_y} {
is_food <- true;
}
loop pos over: obstacle_positions {
ask world_cell grid_at pos {
is_obstacle <- true;
}
}
// Create the forager at position (0, 0)
create forager number: 1 {
my_cell <- world_cell grid_at {0, 0};
location <- my_cell.location;
}
}
}
grid world_cell width: 10 height: 10 neighbors: 4 {
bool is_food <- false;
bool is_obstacle <- false;
rgb color <- #white update: is_obstacle ? rgb(60, 60, 60) : #white;
}
species forager {
world_cell my_cell;
reflex random_move {
// Pick a random direction: 0=up, 1=right, 2=down, 3=left
int direction <- rnd(3);
int new_x <- my_cell.grid_x;
int new_y <- my_cell.grid_y;
switch direction {
match 0 { new_y <- new_y - 1; } // up
match 1 { new_x <- new_x + 1; } // right
match 2 { new_y <- new_y + 1; } // down
match 3 { new_x <- new_x - 1; } // left
}
// Check boundaries and obstacles
if (new_x >= 0 and new_x < grid_size and new_y >= 0 and new_y < grid_size) {
world_cell target <- world_cell grid_at {new_x, new_y};
if (not target.is_obstacle) {
my_cell <- target;
location <- my_cell.location;
}
}
}
aspect default {
draw circle(0.4) color: #blue;
}
}
experiment smart_forager type: gui {
output {
display "Grid World" {
grid world_cell border: #lightgray;
species forager;
graphics "food" {
ask world_cell where each.is_food {
draw circle(0.4) color: rgb(50, 180, 50);
}
}
}
}
}