In a previous tutorial, I discussed some of the powerful list-processing facilities in NetLogo. In this tutorial, we use lists to give agents a sequence of goals.
To facilitate this, we use three agent variables: an identifier id
(currently just a copy of the predefined who
), an agent speed speed
in cells per tick, and a (flat) list goal
of goals, looking like [ "goto" 3 3 "meet" 7 "scatter" "meet" 0 ]
:
turtles-own [
id ;; agent id number or name (usually a copy of "who")
speed ;; agent speed in cells per tick
goal ;; goal list
]
For demonstration purposes, the goals include only:
- goto x y – move in a direct line to the position (x, y)
- meet a – move to the agent with identifier a
- scatter – move to a random position
Goals are executed in sequence, and removed from the front of the goal
list when they are satisfied. Since a goal may consist of one, two, or three list items, we use the following utility functions to remove items from the front of the goal
list (an alternative approach would be to have a list of lists):
to drop-goal
set goal (bf goal)
end
to drop2-goal
set goal (bf (bf goal))
end
to drop3-goal
set goal (bf (bf (bf goal)))
end
The scatter goal is achieved merely by replacing it by goto x y for random x and y. The sentence
operator is used to combine the three-element list for the goto goal with the rest of the existing goal list. If the “verbose” checkbox is selected, the new goal is also printed:
to obey-scatter
let new-x random-xcor
let new-y random-ycor
if (verbose) [ show (list "scattering to" new-x new-y) ]
set goal (sentence (list "goto" new-x new-y) (bf goal))
end
Unknown goals are satisfied merely with an error message:
to obey-unknown [ g ]
show (list "unknown goal" g)
drop-goal
end
The goto x y goal may require multiple steps before it is satisfied. We therefore need a reporter which indicates when the goal has been achieved. There are three cases:
- We are already at (x, y) – only a message is printed
- The distance
d
to (x, y) is less than or equal to the agent’s speed – so that the goal will be reached within one tick - The distance
d
to (x, y) is greater than the agent’s speed – so that we move forward in the desired direction (fd speed
), but indicate that the goal has not yet been reached (report false
):
to-report obey-goto [ x y ] ;; obey "goto x y" command; report true when achieved
let d (distancexy x y)
if-else (d = 0)
[ if (verbose) [ show (list "already at" x y) ]
report true ]
[ facexy x y
if-else (d <= speed)
[ setxy x y
if (verbose) [ show (list "have reached" x y) ]
report true ]
[ fd speed
report false ] ]
end
The meet a goal is similar. However, we need to consider the special case of an agent meeting itself (which is satisfied trivially):
to-report obey-meet [ ag-id ] ;; obey "meet agent" command; report true when achieved
let him (one-of (turtles with [ id = ag-id ]))
if-else (him = self)
[ if (verbose) [ show (list "i am" him) ]
report true ]
[ face him
let d (distance him)
if-else (d <= speed)
[ move-to him
if (verbose) [ show (list "have met" him) ]
report true ]
[ fd speed
report false ] ]
end
Combining these actions together, an agent performs a single step by checking the first item in the goal list and executing the appropriate command. In the case of goto x y and meet a, we remove the appropriate number of elements from the list only if they are satisfied:
to obey
if (goal != []) [
let kind (item 0 goal)
if-else (kind = "goto") [ if (obey-goto (item 1 goal) (item 2 goal)) [ drop3-goal ] ] [
if-else (kind = "meet") [ if (obey-meet (item 1 goal)) [ drop2-goal ] ] [
if-else (kind = "scatter") [ obey-scatter ] [
obey-unknown kind ] ] ] ]
end
The “go” button simply asks all the turtles to execute obey
, stopping when there are zero turtles with nonempty goal lists:
to go
if (count (turtles with [ goal != []]) = 0) [ stop ]
ask turtles [ obey ]
tick
end
The “setup” button creates some turtles, with an initial list of four goals: [ "goto" 3 3 "meet" 7 "scatter" "meet" 0 ]
.
to setup
clear-all
crt 20 [ setxy random-xcor random-ycor
set speed (0.1 + (random-float (max-agent-speed - 0.1)))
set size 3
set id who
set goal [ "goto" 3 3 "meet" 7 "scatter" "meet" 0 ]
set label id ]
reset-ticks
end
Finally, the interface allows a new goal list, such as [ "scatter" "goto" 15 2 ]
, to be added at the end of the existing list (using sentence
and read-from-string
):
to add-goals
ask turtles [
set goal (sentence goal (read-from-string new-goal))
if (verbose) [ show (fput "goal =" goal) ]
]
end
The complete NetLogo file can be found at found at Modeling Commons. There is still the fact that realistic lists of goals will be produced by some kind of planner, but that is another story.
Pingback: Agent goals in NetLogo: The wolf, the goat, and the cabbage | Scientific Gems
Pingback: Planning in NetLogo: The wolf, the goat, and the cabbage again | Scientific Gems
Pingback: NetLogo post summary | Scientific Gems