Step 2. Add people
1. Introduction
In this step, you will create a new breed of agents (humans) and will use the code already present to make them move, eat, reproduce, and die. Humans will also domesticate some of the wolves and feed them when possible.
​
Throughout these steps, we include images of the changes you need to make. Changes to the Interface will be figures, whereas we will provide the code to add in grey boxes. In those boxes, the pieces of code to add will be blue and bold, whereas the pieces of code to remove will be red and italics. Some surrounding code will often be provided to help you see where to make the change. While you could simply copy-paste the code into your model, we highly encourage you to type it in to learn faster.
​
If you hover over the code boxes, you will see the comments appear. We are keeping them hidden most of the time to provide a cleaner view. However, comments help understand what the code does.
2. Add a new model version
This new model version will allow you, the user, to change between the regular sheep-wolves-grass model and your new model that includes humans.
​
In the Interface, right-click on the model-version dropdown menu (called Chooser in NetLogo vocabulary) and select 'Edit'. This will open the window you see here.
​
Delete the "sheep-wolves" line (this will allow us to simplify the code later), and add the following name:
​
"sheep-wolves-humans-grass"
​
Make sure that the name is between quotation marks. It should be orange, as shown in the picture. Orange represents text in NetLogo.
​
Press OK.
​
Now, given that you removed the option of having a model version without grass, clean the setup code so that patches always have the chance of being brown and have a countdown. To do so, remove the parts of the code that are in italics red below:
; Check model-version switch
; if we're not modeling grass, then the sheep don't need to eat to survive
; otherwise each grass' state of growth and growing logic need to be set up
ifelse model-version = "sheep-wolves-grass" [
ask patches [
set pcolor one-of [ green brown ]
ifelse pcolor = green
[ set countdown grass-regrowth-time ]
[ set countdown random grass-regrowth-time ]
]
]
[
ask patches [ set pcolor green ]
]
; Check model-version switch
; if we're not modeling grass, then the sheep don't need to eat to survive
; otherwise each grass' state of growth and growing logic need to be set up
ifelse model-version = "sheep-wolves-grass" [ ; we do not need this anymore as all runs have grass
ask patches [ ; ask all patches to do what's between the square brackets
set pcolor one-of [ green brown ] ; each patch chooses a color between the two
ifelse pcolor = green ; if they chose green...
[ set countdown grass-regrowth-time ] ; they need to set their countdown for when they'll get eaten
[ set countdown random grass-regrowth-time ] ; initialize grass regrowth clocks randomly for brown patches
]
]
[
ask patches [ set pcolor green ] ; we do not need this anymore as all runs have grass
]
ask sheep [
move
if model-version = "sheep-wolves-grass" [
set energy energy - 1
eat-grass
death
]
ask sheep [
move
; in this version, sheep eat grass, grass grows, and it costs sheep energy to move
if model-version = "sheep-wolves-grass" [
set energy energy - 1 ; deduct energy for sheep only if running sheep-wolves-grass model version
eat-grass ; sheep eat grass only if running the sheep-wolves-grass model version
death ; sheep die from starvation only if running the sheep-wolves-grass model version
]
ask wolves [
move
set energy energy - 1
eat-sheep
death
reproduce-wolves
]
if model-version = "sheep-wolves-grass" [ ask patches [ grow-grass ] ]
ask wolves [
move ; calls the move procedure
set energy energy - 1 ; wolves lose energy as they move
eat-sheep ; wolves eat a sheep on their patch (calls the eat-sheep procedure)
death ; wolves die if they run out of energy (calls the death procedure)
reproduce-wolves ; wolves reproduce at a random rate governed by a slider (calls the reproduce-wolves procedure)
]
if model-version = "sheep-wolves-grass" [ ask patches [ grow-grass ] ] ; there is no longer a version without grass
to-report grass
ifelse model-version = "sheep-wolves-grass" [
report patches with [ pcolor = green ]
]
[ report 0 ]
end
to-report grass
ifelse model-version = "sheep-wolves-grass" [ ; there is no longer a version without grass
report patches with [ pcolor = green ] ; reports the number of green patches
]
[ report 0 ] ; as there is no longer a version without grass, this is no longer necessary
end
to display-labels
ask turtles [ set label "" ]
if show-energy? [
ask wolves [ set label round energy ]
if model-version = "sheep-wolves-grass" [ ask sheep [ set label round energy ] ]
]
end
to display-labels
ask turtles [ set label "" ] ; set labels to blank
if show-energy? [ ; if show-energy? is TRUE, the code within brackets will be run...
ask wolves [ set label round energy ] ; ... then the wolves will show their energy (round means no decimals)
if model-version = "sheep-wolves-grass" [ ask sheep [ set label round energy ] ] ; sheep always have energy when there is grass
]
end
3. Add a breed of humans
Go to the Code tab.
​
At the top of the code, you will see that they set two breeds of agents (wolves and sheep). Breeds are useful because they can have their own specific variables and can be called upon directly.
​
Create a new breed called humans.
​
When creating a new breed, you need to provide 1. a plural and 2. a singular name for your breed. Make sure that the order is correct.
​
In the code below, notice that some text is preceded by semicolons. Those are comments that you should use to document what your code does. Every time you change code, try to comment it to keep a log of what the code does and why.
breed [ sheep a-sheep ]
breed [ wolves wolf ]
breed [ humans human ]
breed [ sheep a-sheep ] ; sheep is its own plural, so we use "a-sheep" as the singular
breed [ wolves wolf ]
breed [ humans human ] ; add humans as a breed (plural name first, and singular second)
4. Create a procedure to add humans
At the end of the code, create a new procedure.
​
Remember that a procedure starts by to procedure-name and ends by end.
​
This procedure is very similar to the parts in the setup procedures where we create wolves and sheep. However, it differs in one way:
​
In the original model, the model creates a certain number of sheep and then tells them to disperse to random patches.
​
In this addition, we instead ask random patches each to create on human. Ultimately, it does the same thing, but may be a bit quicker.
;;; OBSERVER PROCEDURE ;;;
to add-humans
​
ask n-of initial-number-humans patches [
sprout-humans 1 [
set shape "person"
set size 2
set color blue
set energy random (2 * wolf-gain-from-food)
]
]
end
;;; OBSERVER PROCEDURE ;;;
to add-humans
; Create as many humans as the slider
ask n-of initial-number-humans patches [ ; This way of creating humans prevents having to give them coordinates
sprout-humans 1 [ ; Create humans, then initialize their variables
set shape "person" ; humans are "person" shaped
set size 2 ; a bit bigger than turtles and wolves
set color blue ; people will be blue for now
set energy random (2 * wolf-gain-from-food) ; the initial energy is up to the gain that wolves get * 2
]
]
end
5. Adding the variables needed
Now that you've added some code, let's try something.
Save your model and then press on the checkmark at the top left on the window. You will see the error message shown here. This message tells you that 'initial-number-humans' is not something that the model recognizes.
​
This is normal. In the add-humans procedure, most of the terms are NetLogo primitives and variables that have already been defined, except for 'initial-number-humans'. In order for the model to know what that refers to, you need to create a global variable with that name that will take on a numerical value.
​
To do so, go to the Interface. Right-click to the right of the World window and select 'Slider'. This will create a new slider and will open the edit window for you.
​
Name this slider 'initial-number-humans'. Set the min to 0 and the maximum to 100. Click Ok. The error should disappear.
​
Here is something important to keep in mind: Use the checkmark often to validate your code as you write it. Checking it often will help you avoid mistakes that cannot easily be fixed.
6. Update the setup procedure to call add-humans
Now that you have created your first procedure, you need to make sure that the model calls it. A procedure that is never called does not do anything.
​
This procedure is meant to create humans when the model is first set up. Therefore, the model will need to call it within the setup procedure.
​
Go to the setup procedure, and add the following piece of code after the code that creates wolves.
​
As you can see, this new piece of code says that if the user chooses the 'sheep-wolves-humans' model-version (which you created earlier in the chooser), the model will call the new procedure.
if model-version = "sheep-wolves-humans-grass"
[ add-humans ]
display-labels
reset-ticks
if model-version = "sheep-wolves-humans-grass" ; check model switch. If applicable, create humans
[ add-humans ] ; call the add-humans procedure
display-labels ; calls the display-labels procedure
reset-ticks ; resets the ticks to 0
7. Try it!
Go back to the Interface and click Setup. You should now have humans spread out on the landscape, with wolves and sheep around as well.
​
This is all great, but what happens if you click Go? The wolves and sheep start moving, but the humans stay in place and do not do anything. Can you figure out why?
​
So far, you have only created this new breed of humans, but nothing in the code tells them to perform a specific action. This is what you will change in the next few steps.
​
For the fun of it, in this simulation, humans will interact with both wolves and sheep.
​
When humans encounter a wolf (when on the same patch), they will either domesticate the wolf or get eaten by it (both with 50% probabilities).
​
Humans will then have to feed the domesticated wolves they encounter. Domesticated wolves will eat sheep less often, which is why they will rely more heavily on humans to get their food.
​
Humans will feed on sheep and grass.
8. Making humans move and die
We are lucky that there is already a procedure that makes both wolves and sheep move. You will use it for humans as well. This shows that a procedure can be called by multiple agents and called multiple times.
​
Similarly, there is already a procedure that makes turtles die when they run out of energy. You can use this one as well.
​
As you want the humans to move and contemplate their own possible death at every step of the simulation, these procedures need to be called in the Go procedure.
​
See below the piece of code to add. You will notice that here again, we first ask which version of the model we are in. Only if the version includes humans will the model ask humans to move, decrease their energy level, and die. This is because in the sheep-wolves-grass version, humans do not get created at all.
if model-version = "sheep-wolves-humans-grass" [
ask humans [
move
set energy energy - 1
death
]
]
if model-version = "sheep-wolves-humans-grass" [ ; checks the version. If there are humans, ask them to do stuff
ask humans [ ; human actions, almost all the same as sheep and wolves
move ; calls the "move" procedure
set energy energy - 1 ; humans also lose energy as they move
death ; humans die when they run out of energy
]
]
9. Making humans reproduce
This part will be a bit more complicated, as you will change some parts of the code as well as add some.
​
Look at the two procedures called reproduce-sheep and reproduce-wolves. Do you notice something? They are almost identical. The only difference is that they each take a different reproduction rate value that is governed by a slider.
​
When coding, we usually try to avoid repeating pieces of code, when possible. So, here, you will create only one reproduce procedure that can be called by sheep, wolves, and humans.
​
To do that, you can give a procedure its own variable, which is defined in the square bracket (see code below). When calling the procedure, you will need to provide a value that will take this temporary variable name and be used within the procedure. This allows sheep, wolves, and humans to call that procedure with their respective reproduction rate values.
​
Here, delete the reproduce-sheep and reproduce-wolves procedures and replace them by the new one, which takes the 'reproduce-rate' variable.
to reproduce [ reproduce-rate ]
if random-float 100 < reproduce-rate [
set energy (energy / 2)
hatch 1 [ rt random-float 360 fd 1 ]
]
end
to reproduce [ reproduce-rate ] ; procedure that requires a value (reproduce-rate)
if random-float 100 < reproduce-rate [ ; throw "dice" to see if you will reproduce
set energy (energy / 2) ; divide energy between parent and offspring
hatch 1 [ rt random-float 360 fd 1 ] ; hatch an offspring and move it forward 1 step
]
end
10. Update the reproduction code
Now that you changed the reproduction procedures, if you click on the Checkmark, it will give you an error, because sheep and wolves are now calling procedures that do not exist. You need to fix this.
​
In the Go procedure, for both sheep and wolves, change the line of code that simply says 'reproduce-sheep' or 'reproduce-wolves' by 'reproduce' followed by the name of the breed's reproduction rate slider. See below.
​
You will also need to add the same for humans, but before doing so, go to the Interface and create a slider named human-reproduce with a range of values from 0-10. You can add a % in the 'Units' box so that the slider shows we are using this value as a percentage.
Call the reproduction procedure in the humans part of the Go procedure.
ask sheep [
move
set energy energy - 1
eat-grass
death
reproduce sheep-reproduce
]
ask wolves [
move
set energy energy - 1
eat-sheep
death
reproduce wolf-reproduce
]
if model-version = "sheep-wolves-humans-grass" [
ask humans [
move
set energy energy - 1
death
reproduce humans-reproduce
]
]
ask sheep [
move
; in this version, sheep eat grass, grass grows, and it costs sheep energy to move
set energy energy - 1 ; deduct energy for sheep only if running sheep-wolves-grass model version
eat-grass ; sheep eat grass only if running the sheep-wolves-grass model version
death ; sheep die from starvation only if running the sheep-wolves-grass model version
reproduce sheep-reproduce ; sheep reproduce at a random rate governed by a slider
]
ask wolves [
move ; calls the move procedure
set energy energy - 1 ; wolves lose energy as they move
eat-sheep ; wolves eat a sheep on their patch (calls the eat-sheep procedure)
death ; wolves die if they run out of energy (calls the death procedure)
reproduce wolf-reproduce ; wolves reproduce at a random rate governed by a slider
]
if model-version = "sheep-wolves-humans-grass" [ ; checks the version. If there are humans, ask them to do stuff
ask humans [ ; human actions, almost all the same as sheep and wolves
move ; calls the "move" procedure
set energy energy - 1 ; humans also lose energy as they move
death ; humans die when they run out of energy
reproduce humans-reproduce ; wolves reproduce at a random rate governed by a slider
]
]
11. Provide some food to humans
At this point, if you click setup and go, you will see the humans move, but after a while, they will all die. Can you understand why?
​
They do not have anything to eat, and every time they move, they lose some energy. So you need to provide them with some source of food.
​
As stated earlier, we want humans to feed on sheep (meat!) and grass (some veggies are good too!). To do that, let's create a new procedure.
​
Humans will eat sheep only at a certain rate controlled by a slider, called rate-sheep-eating. Go to the Interface and create that slider, with a range of values from 0-50%.
​
Then, create the new procedure called humans-eat.
​
In this procedure, you will be introduced to the ifelse statement. This takes a condition (here: if a random value below 100 is lower than the slider value of rate-sheep-eating). If this condition is true, the model runs the code that is within the first set of square brackets following the condition. If the condition is false, the model runs the code that is in the second set of square brackets.
;;; HUMAN PROCEDURE ;;;
to humans-eat
ifelse random 100 < rate-sheep-eating [
let prey one-of sheep-here
if prey != nobody [
ask prey [ die ]
set energy energy + wolf-gain-from-food
]
][
if pcolor = green [
set pcolor brown
set energy energy + (wolf-gain-from-food / 4)
]
]
​
end
;;; HUMAN PROCEDURE ;;;
to humans-eat
; this is a modified version of the sheep-eat
ifelse random 100 < rate-sheep-eating [ ; Humans will eat sheep only a certain % of time, based on a slider.
; If the random value is below rate-sheep-eating, the human eats a sheep.
let prey one-of sheep-here ; grab a random sheep
if prey != nobody [ ; did we get one? if so,
ask prey [ die ] ; kill it, and...
set energy energy + wolf-gain-from-food ; get energy from eating. For simplicity, the same energy as wolves
]
][ ; If not eating a sheep, still getting some pretty good nutrients from cultivated grass (wheat?)
if pcolor = green [
set pcolor brown
set energy energy + (wolf-gain-from-food / 4) ; But still not as good as eating a sheep
]
]
​
end
12. Integrate the food to the Go procedure
You created a procedure that will allow humans to eat, but here again, you need to make sure that the humans actually call that procedure within the code. As we want them to try to eat at every step, we can integrate this procedure within the Go procedure as well, before they die (so even starving, they always have a chance to get last nutrients before dying).
if model-version = "sheep-wolves-humans-grass" [
ask humans [
move
set energy energy - 1
humans-eat
death
reproduce humans-reproduce
]
]
if model-version = "sheep-wolves-humans-grass" [ ; checks the version. If there are humans, ask them to do stuff
ask humans [ ; human actions, almost all the same as sheep and wolves
move ; calls the "move" procedure
set energy energy - 1 ; humans also lose energy as they move
humans-eat ; Humans eat some of the sheep that are on their patch or the grass if available
death ; humans die when they run out of energy
reproduce humans-reproduce ; wolves reproduce at a random rate governed by a slider
]
]
13. Domesticate the wolves
As mentioned above, humans will now have the opportunity to either get eaten by wolves they encounter or domesticate them (50-50 chance). Domesticated wolves will eat sheep less often, as they will be fed by humans instead.
To distinguish between domesticated and wild wolves, you need to assign a new variable to the wolf breed. This needs to be done in the first part of the code. Go to the top of the code, but after the breeds are created, and add the piece of code that will assign the variable "domesticated?" to wolves.
​
Notice in the code below that only wolves have this variable. This means that you cannot ask a domesticated sheep to do something. Only wolves. This shows you why creating breeds is a good thing. It allows you to restrict the different variables to the agents that use them.
​
After creating this new variable, set up its default value (false) in the setup procedure, create a new domesticate-wolves procedure, and make sure that you call it within Go.
create-wolves initial-number-wolves
[
set shape "wolf"
set color black
set size 2
set energy random (2 * wolf-gain-from-food)
setxy random-xcor random-ycor
set domesticated? false
]
create-wolves initial-number-wolves ; create the wolves, then initialize their variables
[
set shape "wolf"
set color black
set size 2 ; easier to see
set energy random (2 * wolf-gain-from-food)
setxy random-xcor random-ycor
set domesticated? false ; by default, wolves are wild
]
turtles-own [ energy ]
wolves-own [ domesticated? ]
turtles-own [ energy ] ; All entities have energy
wolves-own [ domesticated? ] ; To know if the wolf is domesticated
;;; HUMAN PROCEDURE ;;;
to domesticate-wolves
let friend one-of wolves-here
if friend != nobody [
if [ domesticated? ] of friend = false [
ifelse random 100 < 50 [
ask friend [
set domesticated? true
set color 2
]
][
ask friend [
set energy energy + ( wolf-gain-from-food * 1.5 )
]
die
]
]
]
end
;;; HUMAN PROCEDURE ;;;
to domesticate-wolves
; when a human encounters a wild wolf (on same patch), there is a 50-50 chance they will domesticate it...
; or get eaten
let friend one-of wolves-here ; grab a random wolf on the same patch
if friend != nobody [ ; did we get one? if so,
; 50% of the time, the human will domesticate the wolf if it is wild
if [ domesticated? ] of friend = false [ ; check the domesticated status. If still wild
ifelse random 100 < 50 [ ; throw the dice. "random 100" will give values between 0-99 inclusively.
ask friend [ ; this bracket is if the condition above is true (if the value is < 50)
set domesticated? true ; this variable becomes true
set color 2 ; Transform the wolf into a dog (set color to grey)
] ; end of the "if" bracket (if dice roll < 50)
][ ; the rest of the time (50% of the time), the wild wolf will kill the human
ask friend [
set energy energy + ( wolf-gain-from-food * 1.5 ) ; the wild wolf gets some food out of the human
] ; end of the "else" bracket
die ; and the human dies
]
]
]
end
if model-version = "sheep-wolves-humans-grass" [
ask humans [
move
set energy energy - 1
humans-eat
domesticate-wolves
death
reproduce humans-reproduce
]
if model-version = "sheep-wolves-humans-grass" [ ; checks the version. If there are humans, ask them to do stuff
ask humans [ ; human actions, almost all the same as sheep and wolves
move ; calls the "move" procedure
set energy energy - 1 ; humans also lose energy as they move
humans-eat ; Humans eat some of the sheep that are on their patch or the grass if available
domesticate-wolves ; Humans domesticate some of the wolves they encounter
death ; humans die when they run out of energy
reproduce humans-reproduce ; wolves reproduce at a random rate governed by a slider
]
14. Change the wolves' behavior
You are almost done with the first step in creating your own Game of Thrones ABM!
​
As you have now changed the code so that humans domesticate 50% of the wolves they encounter, you need you change the code so that:
​
1. Domesticated wolves do not eat sheep as often (let's say they became herding dogs).
​
2. Humans feed the domesticated dogs they encounter to offset the fact that those wolves don't eat sheep anymore (we wouldn't want our wolves to starve).
​
Let's deal with n.1 first. For this one, you will have to add an if else statement to the Go procedure, as shown below. This piece of code replaces the simple 'eat-sheep' line (so delete that line). It now asks wolves to eat sheep only if they are not domesticated. If they are domesticated, they will only eat sheep if their energy level is getting dangerously low (<20).
​
ask wolves [
move
set energy energy - 1
ifelse not domesticated? [
eat-sheep
][
if energy < 20 [
eat-sheep
]
]
eat-sheep
death
reproduce wolf-reproduce
]
ask wolves [
move ; calls the move procedure
set energy energy - 1 ; wolves lose energy as they move
ifelse not domesticated? [ ; if the wolves are still wild... (same as saying "if domesticated? = FALSE")
eat-sheep ; ...they eat a sheep on their patch (only if they are still wild)
][ ; if the wolves are domesticates
if energy < 20 [ ; ...and only if they are starving...
eat-sheep ; ... then they eat a sheep if there is one around
] ; end of the "if energy < 20" bracket
] ; end of the "else" bracket (if domesticated)
eat-sheep ; wolves eat a sheep on their patch (calls the eat-sheep procedure)
death ; wolves die if they run out of energy (calls the death procedure)
reproduce wolf-reproduce ; wolves reproduce at a random rate governed by a slider
]
15. Feed the domesticated wolves
To feed the domesticated wolves, create a new procedure called 'humans-feed-animals'.
​
In this procedure, notice that we use the term "let" followed by the name "dogs." The NetLogo term 'let' creates a temporary variable that can be accessed only within the space it is created. Here, for example, we create a temporary variable that identifies all wolves that are domesticated under the name "dogs." Within the procedure, the model can call on that variable the same it would call global variables or breeds. For example, here, the model asks one of the dogs (domesticated wolves) to eat part of a sheep (the -20 energy means that the dog shares the sheep with the human).
​
As always, you will need to make sure that the code calls that procedure somewhere. As we want humans to feed wolves at every tick if a dog is around, we can call this procedure within the Go procedure, after calling the domesticate-wolves procedure.
​
to humans-feed-animals
let dogs wolves-here with [ domesticated? = true ]
let prey sheep-here
if any? dogs and any? prey [
ask one-of dogs [
eat-sheep
set energy energy - 20
]
set energy energy + 20
]
end
to humans-feed-animals
; Identifies the dogs and feed them by sharing a sheep if there is one around
let dogs wolves-here with [ domesticated? = true ] ; temporary variable to identify dogs on the same patch
let prey sheep-here ; check if there are sheep that can be fed to the dog
if any? dogs and any? prey [ ; if there are any dogs here and a sheep they can be fed with...
ask one-of dogs [
eat-sheep ; the human tells its dog to hunt a sheep ...
set energy energy - 20 ; ... and take some of the nutrients for itself (but not all of it)
] ; end of the "ask one-of dogs"
set energy energy + 20 ; the human also gets nutrients from the hunted sheep
] ; end of the "if any? dogs" bracket
end
if model-version = "sheep-wolves-humans-grass" [
ask humans [
move
set energy energy - 1
humans-eat
domesticate-wolves
humans-feed-animals
death
reproduce humans-reproduce
]
]
if model-version = "sheep-wolves-humans-grass" [ ; checks the version. If there are humans, ask them to do stuff
ask humans [ ; human actions, almost all the same as sheep and wolves
move ; calls the "move" procedure
set energy energy - 1 ; humans also lose energy as they move
humans-eat ; Humans eat some of the sheep that are on their patch or the grass if available
domesticate-wolves ; Humans domesticate some of the wolves they encounter
humans-feed-animals ; humans feed their domesticated wolves
death ; humans die when they run out of energy
reproduce humans-reproduce ; wolves reproduce at a random rate governed by a slider
]
]
16. Update the Interface populations plot
As you have added a new breed of agents, and wolves can now become dogs, let's add those to the populations plot on the interface.
​
In the Interface, right-click on the plot, and select "Edit."
​
In the Pen update command window next to the wolves pen, change the code so it reads "plot count wolves with [ domesticated? = false ]"
​
Click on the "Add Pen" button. This creates a new line.
Change the name of the pen for "dogs" and write "plot count wolves with [ domesticated? = true ]" in the Pen update command box.
​
Add a new pen for humans. The Pen update command box should read "plot count humans". Set the pen color to blue (double-click on the color and choose the new one).
​
Finally, delete the pen for grass.
Congratulations on finishing Step 2!
Congratulations, you now should have a model that integrates humans to the basic predator-prey model. We added some complexity with the domestication, just for fun and to explore NetLogo dynamics a bit.
​
Now that you are done with this section, feel free to explore how adding humans change the balance between wolves and sheep. Can you find settings where an equilibrium can be reached? It may be harder than you think!
​
If you want to see the finished model for this step, download it here.
​
Next step, we will leave the abstract landscape behind and integrate different GIS data of Westeros. See you there!