The puzzle of the wolf, goat, and cabbage is an ancient one – it appears in the Propositiones ad acuendos iuvenes, attributed to Alcuin of York, and written around 800 AD. The NetLogo solution described here builds on a modified version of my Goals in NetLogo tutorial.
The goto
goal here is the same as for the previous tutorial, and the meet
goal differs only in containing a reference to an agent, rather than a string identifier.
The wait
goal contains a reporter task, and succeeds when that task returns “true.” The instruct
goal gives aditional goals to another agent or (with an empty list) erases another agent’s goals. The pickup
and drop
goals set the carrier
variable of another agent to mark it as being carried. Agents being carried always follow the agent carrying them. The embark
and disembark
goals are used by the man to be carried by the boat.
Domain-specific goals include eat
, satisfied by the wolf and goat if they succeed in devouring their favourite food, together with go-left
and go-right
, the first of which expands to the goal list ["meet" boat "embark" "instruct" boat ["goto" (1 - bank) 0] "wait" (task at-left) "disembark" "goto" (- (bank + 3)) 0)]
, and the second of which expands to something similar. Note the use of task
to create a reporter task from the reporter at-left
.
The problem is solved when the man has the goal list ["drop" wolf "drop" cabbage "go-left" "drop" goat "go-right" "pickup" wolf "go-left" "pickup" goat "drop" wolf "go-right" "pickup" cabbage "drop" goat "go-left" "drop" cabbage "go-right" "pickup" goat "go-left"]
. The sequence of picking up and dropping entities ensure that the wolf and goat are unable to carry out their eating goals. The top-level goal procedure is:
to obey
if (carrier != nobody) [
move-to carrier
]
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 = "wait") [ if (runresult (item 1 goal)) [ drop2-goal ] ] [
if-else (kind = "instruct") [ obey-instruct (item 1 goal) (item 2 goal)
drop3-goal ] [
if-else (kind = "pickup") [ obey-pickup (item 1 goal)
drop2-goal ] [
if-else (kind = "drop") [ obey-drop (item 1 goal)
drop2-goal ] [
if-else (kind = "embark") [ obey-embark
drop-goal ] [
if-else (kind = "disembark") [ obey-disembark
drop-goal ] [
if-else (kind = "eat") [ if (obey-eat (item 1 goal)) [ drop2-goal ] ] [
if-else (kind = "go-left") [ obey-go-left ] [
if-else (kind = "go-right") [ obey-go-right ] [
obey-unknown kind ] ] ] ] ] ] ] ] ] ] ] ]
end
Specific goal commands include:
to obey-disembark
if (verbose?) [ show (list "disembarking") ]
set carrier nobody
end
to obey-embark
if (verbose?) [ show (list "embarking") ]
set carrier boat
end
to obey-pickup [ him ]
ask him [ set carrier myself ]
if (verbose?) [ show (list "picking up" ([label] of him)) ]
end
to obey-drop [ him ]
if-else ([ carrier ] of him = self)
[ ask him [ set carrier nobody ]
if (verbose?) [ show (list "dropping" ([label] of him)) ] ]
[ show (list "CANNOT DROP" ([label] of him)) ]
end
to obey-instruct [ him g ]
if-else (g = [])
[ ask him [ set goal [] ] ]
[ ask him [ set goal (sentence goal g) ] ]
if (verbose?) [ show (list "instructing" ([label] of him) "to" g) ]
end
Initialisation code is as follows, with the entire program available at Modeling Commons. See also here for a video. For agents to develop the solution on their own, a planner is still needed.
turtles-own [
speed ;; agent speed in cells per tick
goal ;; goal list
carrier ;; agent carrying this agent (or "nobody")
]
globals [
wolf
goat
cabbage
man
boat
verbose? ;; if true, agents print what they are doing
bank ;; location of river bank (+ or -)
]
to setup
clear-all
set bank 13
set verbose? true
ask patches with [ pxcor <= (- bank) or pxcor >= bank ] [set pcolor green ]
ask patches with [ pxcor > (- bank) and pxcor < bank ] [set pcolor blue ]
crt 5 [ setxy (bank + 3) 0
set speed 0.01
set size 3
set carrier nobody
set goal [ ] ]
set wolf (turtle 0)
set goat (turtle 1)
set cabbage (turtle 2)
set man (turtle 3)
set boat (turtle 4)
let labels [ "wolf" "goat" "cabbage" "" "boat" ]
ask turtles [ set label (item who labels) ]
ask man [ set shape "person"
set size 4
set goal (list "drop" wolf "drop" cabbage "go-left" "drop" goat "go-right" "pickup" wolf "go-left"
"pickup" goat "drop" wolf "go-right" "pickup" cabbage "drop" goat "go-left"
"drop" cabbage "go-right" "pickup" goat "go-left "instruct" wolf [] "instruct" goat [])
set color red ]
ask cabbage [ set shape "plant"
set carrier man
set color 53 ]
ask boat [ set size 5
set xcor (bank - 1)
set speed (speed * 2)
set color brown ]
ask goat [ set shape "cow"
set goal (list "eat" cabbage)
set carrier man
set color white ]
ask wolf [ set shape "wolf"
set goal (list "eat" goat)
set carrier man
set color black ]
reset-ticks
end
XKCD has his own take on this problem:
Pingback: Planning in NetLogo: The wolf, the goat, and the cabbage again | Scientific Gems
Pingback: NetLogo post summary | Scientific Gems