Step 5. Add conflict
1. The Prisoner's dilemma
While we wish we could model the intricacies of the Song of Ice and Fire conflicts, it would be very complicated. As models are abstractions of complex systems, we thought instead that using the classic prisoner's dilemma dynamics would still provide interesting patterns.
​
The prisoner's dilemma goes as follow: two people (let's say X and Y) play a game. They have two choices: they can cooperate (C) or defect (D). Depending on their choice, X and Y get different outcomes.
​
If X cooperates, but Y defects, Y gets a payoff P, but X gets nothing.
If both X and Y cooperate, they both get a payoff P/2.
If both X and Y defect, none of them get anything.
​
Therefore, it is more advantageous to defect, but only if the other person cooperates.
​
In this step, you will add the prisoner's dilemma algorithm to the model, using subjective probability of cooperating for each house (e.g. Lannisters do not cooperate often, but Starks do...). The winner of the highest payoff gets to increase its territory. Let's see how the different strategies affect each houses!
​
The first step is to create a breed of houses, which will play the prisoner's dilemma games. Create the breed and give it its specific variables.
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 first, then singular)
breed [ cities city ] ; add cities as a breed
breed [ houses a-house ] ; houses will play the prisoner's dilemma
breed [ sheep a-sheep ]
breed [ wolves wolf ]
breed [ humans human ]
breed [ cities city ]
breed [ houses a-house ]
houses-own [
name ; house name to call specific ones
my-color ; house color
throne-score ; score of the prisoner's dilemma game
cooperate? ; determines the probability of cooperation
rival-list ; list of neighbors against which they will play
defeated? ; will record if the house still holds cities
]
houses-own [
name
my-color
throne-score
cooperate?
rival-list
defeated?
]
2. Create a list of houses
The next step is to create a list of houses that will play the game. As the kingdoms are defined by their color in the model, the simplest way to do that is to create a list of the used NetLogo colors.
As the Greyjoys do not hold land on the main continent, we have to remove them from the list for now because players need to be able to expand their territory on land, and having to skip over the water would be too complicated. Improving this to include the Greyjoys could be an edit you do when you finish the whole model!
​
Create a global variable that will record the list of all potential players. Then compute that list, using the reporter identify-houses.
​
Here, we created the list within a reporter procedure. As you will notice, this procedure starts by to-report rather than simply to. This means that the procedure needs to report one - and only one - thing at the end. In this case, this procedure reports the list of colors.
​
Reporters are very useful to reduce repeating code and speed up your models.
​
You will call that reporter in the next section.
globals [
max-sheep ; don't let the sheep population grow too large
land-patches ; keeps track of the patches that are on land
players ; records who will play the prisoner's dilemma
]
globals [
max-sheep
land-patches
players
]
to-report identify-houses
; this provides a list of GoT houses that still hold land
let color-list remove-duplicates [ house-color ] of patches with [ land? ]
set color-list remove 32 color-list ; 32 (Greyjoys) has to be removed in order for the territories to work correctly
set color-list remove 8 color-list ; Wildlings also do not play
set color-list remove 0 color-list ; Night's Watch also do not play
report color-list
end
3. Create overarching houses
You need to have each house play against one another, but how can you do this? One possibility would be to assign one human per house to be the player, but then what would happen if that human died of a lack of food?
​
The simplest way to do this is to use the house breed: create one "house" agent per house, and make them invisible, because they represent the whole territory rather than just one person.
​
Write a new procedure that creates those 'house' agents and set up their variables. As each house agent needs to record who they will play the prisoner's dilemma game against, it needs to call the identify-houses reporter you just created to get the list of possible players. To understand how the reporter fits within the code, think of it this way: when reading the code, the reporter takes on the value it reports. Does that make sense?
​
Integrate that new setup-got-houses at the end of the setup-houses procedure. The reason why we do not call this new procedure within setup is because we need to import the territory polygon before creating the house agents and because we will add code to setup-houses that will need to be run after setup-got-houses.
to setup-got-houses ; observer procedure
set players identify-houses ; creates the list of potential players of the prisoner's dilemma
; the foreach loop iterates through the list. x represents each entry of the list as it goes through.
foreach players [
x -> create-houses 1 [
set hidden? true ; the agents only make decisions, so seeing them is unimportant
let one-patch one-of patches with [ house-color = x ] ; identify a patch that matches that house's territory
move-to one-patch ; put the agents in its territory
set name [ house ] of one-patch ; the agent records its house
set my-color x ; the agent records its house's color
set rival-list [] ; set up an empty list
]
]
end
to setup-got-houses
set players identify-houses
foreach players [
x -> create-houses 1 [
set hidden? true
let one-patch one-of patches with [ house-color = x ]
move-to one-patch
set name [ house ] of one-patch
set my-color x
set rival-list []
]
]
end
to setup-houses ; observer procedure
; load the vector dataset of houses to the temporary houses-basemap variable
let houses-basemap gis:load-dataset "../data/W_political_revised.shp"
; set the min and max threshold for patches to decide if they are part of the polygon or not
; to be a part, a patch has to be covered at least 50% by a polygon
gis:set-coverage-minimum-threshold 0.5
gis:set-coverage-maximum-threshold 1
; ask patches to set their house variable based on the claimbedBy variable of the polygon they fall on
gis:apply-coverage houses-basemap "CLAIMEDBY" house
; some cleaning necessary as the polygons do not fit perfectly with the raster
let list-houses remove-duplicates ([ house ] of patches with [ land? = true ])
set list-houses remove "no one" list-houses ; removes the name associated with water
ask patches [
if land? = false and member? house list-houses ; houses that fall within a polygon but are water...
[ set house "no one" ] ; ... change their house to "no one" (water)
]
setup-got-houses ; call the setup-got-houses procedure
end
to setup-houses
let houses-basemap gis:load-dataset "../data/W_political_revised.shp"
gis:set-coverage-minimum-threshold 0.5
gis:set-coverage-maximum-threshold 1
gis:apply-coverage houses-basemap "CLAIMEDBY" house
let list-houses remove-duplicates ([ house ] of patches with [ land? = true ])
set list-houses remove "no one" list-houses
ask patches [
if land? = false and member? house list-houses
[ set house "no one" ]
]
setup-got-houses
end
4. Add Interface variables
While we want to see how the prisoner's dilemma affect the houses' dynamics and territories, we do not want houses to play the games in all the simulations we run. Therefore, we need to add a switch that will determine when the prisoner's dilemma is played and when there is peace.
​
In addition, we want to explore how different probabilities of cooperating may change the political landscape. To do that, we will have two scenarios that affect the way the game is played. One will be random, and the other will be based on our subjective assessments of each house's willingness to cooperate.
​
Go to the Interface and add a switch named conflict?.
​
Then, add a chooser called battle-strategy with the following possibilities:
"random"
"faithful to the Story"
​
Finally, add a slider called chance-of-cooperation with values from 0-100% that will be used to affect the random scenario.
​
Create a new procedure that will update the players and the houses' defeat status. Change the go procedure to call that procedure if conflict? in ON.
to update-players ; observer procedure
ask houses [
set defeated? true ; resets the defeat status for a clean slate before each battle
]
set players identify-houses ; updates the list of players that still hold land
foreach players [
x -> ask houses with [ my-color = x ][ ; the houses of players still active set their defeated? to false
set defeated? false
]
]
end
to update-players
ask houses [
set defeated? true
]
set players identify-houses
foreach players [
x -> ask houses with [ my-color = x ][
set defeated? false
]
]
end
ask patches [ grow-grass ]
if conflict? [ ; if conflict? switch is ON (same as "if conflict? = true"), houses will fight using the prisoner's dilemma
update-players ; update the list of possible players
]
ask patches [ grow-grass ]
if conflict? [
update-players
]
5. Set up who will cooperate
Now that you have created those variables, it is time to update the code so that they are taken into consideration. First, create two new procedures that uses the scenario chosen on the Interface and assign the appropriate cooperation probabilities to each houses.
​
Here we use three different small procedures instead of a single (and bigger one). This is actually good coding practice. Keep your procedures as small as possible to make sure that each part works correctly. It is easier to troubleshoot code when it has lots of small parts than when it's all collated into big ones.
to houses-fight-for-territory ; observer procedure
; resets the values at every tick so the old fight is forgotten
ask houses [ set throne-score 0 ]
; if the chosen strategy is random, houses call the decide-random-strategy procedure, which...
; ... determines the house's probabilities of cooperating
ifelse battle-strategy = "Random" [
ask houses [
set-random-strategy
]
][ ; if the chosen strategy chosen is not random, houses call the decide-faithful-to-show-strategy procedure
; this determines the house's probabilities of cooperating
ask houses [
set-faithful-to-show-strategy
]
]
end
to houses-fight-for-territory
ask houses [ set throne-score 0 ]
ifelse battle-strategy = "Random" [
ask houses [
set-random-strategy
]
][
ask houses [
set-faithful-to-show-strategy
]
]
end
;;; HOUSE PROCEDURE ;;;
to set-random-strategy
; each house rolls the die and if the value is below the value on the slider, they will cooperate
; random 100 will give you one value between 0-99
; if we want a chance of cooperation of 50%, saying random 100 < 50 works because...
; 50 values fall below 50 (0-49) and 50 values fall at or above (50-99)
ifelse ( random 100 ) < chance-of-cooperation [
set cooperate? true
][
set cooperate? false
]
end
;;; HOUSE PROCEDURE ;;;
to set-random-strategy
ifelse ( random 100 ) < chance-of-cooperation [
set cooperate? true
][
set cooperate? false
]
end
;;; HOUSE PROCEDURE ;;;
to set-faithful-to-show-strategy
; the chance of cooperation is arbitrary based on what we read in ASOIAF
let faithful-chance-of-cooperation 0
if name = "Tyrell" [ set faithful-chance-of-cooperation 70 ]
if name = "Arryn" [ set faithful-chance-of-cooperation 25 ]
if name = "Targaryen" [ set faithful-chance-of-cooperation 25 ]
if name = "Tully" [ set faithful-chance-of-cooperation 75 ]
if name = "Martell" [ set faithful-chance-of-cooperation 35 ]
if name = "Stark" [ set faithful-chance-of-cooperation 100 ]
if name = "Baratheon" [ set faithful-chance-of-cooperation 50 ]
if name = "Lannister" [ set faithful-chance-of-cooperation 15 ]
; each house still rolls a die and if the value is below their chance of cooperation, they will cooperate
ifelse ( random 100 ) < faithful-chance-of-cooperation [
set cooperate? true
][
set cooperate? false
]
end
;;; HOUSE PROCEDURE ;;;
to set-faithful-to-show-strategy
let faithful-chance-of-cooperation 0
if name = "Tyrell" [ set faithful-chance-of-cooperation 70 ]
if name = "Arryn" [ set faithful-chance-of-cooperation 25 ]
if name = "Targaryen" [ set faithful-chance-of-cooperation 25 ]
if name = "Tully" [ set faithful-chance-of-cooperation 75 ]
if name = "Martell" [ set faithful-chance-of-cooperation 35 ]
if name = "Stark" [ set faithful-chance-of-cooperation 100 ]
if name = "Baratheon" [ set faithful-chance-of-cooperation 50 ]
if name = "Lannister" [ set faithful-chance-of-cooperation 15 ]
ifelse ( random 100 ) < faithful-chance-of-cooperation [
set cooperate? true
][
set cooperate? false
]
end
6. Fight!!!
It is time for battle!
​
Create a new fight procedure where houses will play the prisoner's dilemma game with one of the other houses and calculate their score.
​
In this model, we chose to set the payoffs in the following way:
If X cooperates and Y defects, X gets 0, and Y gets 100.
If both X and Y cooperate, they each get 25.
If both X and Y defect, they each get -100.
​
Notice in this procedure that we used a code shortcut. When you want to check if a variable equals true, you can simply call that variable. The "= true" is implied.
​
Update the houses-fight-for-territory procedure so that the houses call the new fight procedure after determining if they will cooperate or defect.
​
Update the go procedure to call the houses-fight-for-territory procedure.
​
Finally, to see who wins at every step, go to the Interface and create a monitor that shows the name of the winning house.
;;; HOUSE PROCEDURE ;;;
to fight
set rival-list players ; the house updates the identity of all the GoT houses still playing
set rival-list remove my-color rival-list ; the house cannot play against itself
; chooses one of the other houses to play against (here, chooses among a list of colors)
let a-rival-number one-of rival-list
; identifies the name of the house that holds that color
let other-house one-of houses with [ a-rival-number = my-color ]
; identifies the strategy of the chosen rival house (for code simplicity below)
let other-house-strategy? [ cooperate? ] of other-house
; if the current house cooperates
ifelse cooperate? [
ifelse other-house-strategy? [ ; and the rival also cooperates
set throne-score throne-score + 25 ; both houses get a score of 25
ask other-house [
set throne-score throne-score + 25
]
][ ; if the rival defects, this house gets nothing
set throne-score throne-score + 0
ask other-house [ ; and the rival gets 100
set throne-score throne-score + 100
]
]
][ ; if the current house defects
ifelse other-house-strategy? [ ; and the rival cooperates
set throne-score throne-score + 100 ; the current house gets 100
ask other-house [ ; and the rival gets nothing
set throne-score throne-score + 0 ; this code is just for symmetry and is not as it does not change the variable
]
][ ; but if the rival also defects
set throne-score throne-score - 100 ; both houses get their score reduced by 100
ask other-house [
set throne-score throne-score - 100
]
]
]
end
;;; HOUSE PROCEDURE ;;;
to fight
set rival-list players
set rival-list remove my-color rival-list
let a-rival-number one-of rival-list
let other-house one-of houses with [ a-rival-number = my-color ]
let other-house-strategy? [ cooperate? ] of other-house
ifelse cooperate? [
ifelse other-house-strategy? [
set throne-score throne-score + 25
ask other-house [
set throne-score throne-score + 25
]
][
set throne-score throne-score + 0
ask other-house [
set throne-score throne-score + 100
]
]
][
ifelse other-house-strategy? [
set throne-score throne-score + 100
ask other-house [
set throne-score throne-score + 0
]
][
set throne-score throne-score - 100
ask other-house [
set throne-score throne-score - 100
]
]
]
end
to houses-fight-for-territory ; observer procedure
; resets the values at every tick so the old fight is forgotten
ask houses [ set throne-score 0 ]
; if the chosen strategy is random, houses call the decide-random-strategy procedure, which...
; ... determines the house's probabilities of cooperating
ifelse battle-strategy = "Random" [
ask houses [
set-random-strategy
]
][ ; if the chosen strategy chosen is not random, houses call the decide-faithful-to-show-strategy procedure
; this determines the house's probabilities of cooperating
ask houses [
set-faithful-to-show-strategy
]
]
; then the houses that are still undefeated fight
ask houses with [ defeated? = false ][
fight
]
end
to houses-fight-for-territory
ask houses [ set throne-score 0 ]
ifelse battle-strategy = "Random" [
ask houses [
set-random-strategy
]
][
ask houses [
set-faithful-to-show-strategy
]
]
ask houses with [ defeated? = false ][
fight
]
end
if conflict? [ ; if conflict? switch is ON (same as "if conflict? = true"), houses will fight using the prisoner's dilemma
update-players ; update the list of possible players
if length players > 1 [ ; the houses fight only if there are more than one house left
houses-fight-for-territory
]
]
if conflict? [
update-players
if length players > 1 [
houses-fight-for-territory
]
]
7. Update the territories' sizes
The winner gets part of its neighbors' territories.
For this part, the extent of patches that will change allegiance will be based on the extent by which the winner's throne score is bigger than the average.
​
First, add a new average-household-strength global variable that will take in the average of all throne scores.
​
Add a border? variable to patches.
​
Then, create a new procedure that make the winner's border expand. This is a pretty long procedure.
​
You also need to create a new procedure that updates the borders as they change as well as a new procedure that changes the islands' allegiance when their house has lost all the main land.
​
After creating those, update the houses-fight-for-territory procedure to call the new adjust-territory procedure. Lots of code!!
globals [
max-sheep ; don't let the sheep population grow too large
land-patches ; keeps track of the patches that are on land
players ; records who will play the prisoner's dilemma
average-household-strength ; calculates the average throne score
]
globals [
max-sheep ; don't let the sheep population grow too large
land-patches ; keeps track of the patches that are on land
players ; records who will play the prisoner's dilemma
average-household-strength ; calculates the average throne score
]
patches-own [
countdown ; used to trigger grass regrowth
land? ; boolean that identifies is a cell is land
wall? ; boolean that identifies if the cell overlaps the wall (and thus is part of the wall)
house ; identifies which house owns the cell
house-color ; to show the extent of each house's territory
road? ; identify if the patch is part of a road
border? ; identify if a patch is at the border between two house territories
]
patches-own [
countdown
land?
wall?
house
house-color
road?
border?
]
to adjust-territory ; observer procedure
; Math time - much of this could be calculated in a line, but this is more readable
let undefeated-houses houses with [ defeated? = false ]
let total-houses count undefeated-houses ; records the number of houses that are still fighting
let total-score sum [ throne-score ] of undefeated-houses ; calculates the throne-score of houses
set average-household-strength ( total-score / total-houses ) ; calculates the average throne score
; Temp variables that identify who is winning the throne and who is losing
let best-house one-of undefeated-houses with-max [ throne-score ]
let worst-house one-of undefeated-houses with-min [ throne-score ]
; Temp variables that record the different throne scores in play, as well as the range.
let max-score [ throne-score ] of best-house
let min-score [ throne-score ] of worst-house
let range-of-scores abs ( max-score - min-score )
let score-difference ( max-score - average-household-strength ) ; The difference of the max score from the average score
let percent-to-adjust 0 ; setting up a temp variable that will be changed later
; If range-of-scores > 0 (there is difference), percent-to-adjust becomes the score-difference divided by the range of scores.
; This will be used later to adjust the territory by a percentage of the winning range
; (i.e., the higher the score, the more territory expanded)
if range-of-scores > 0 [ set percent-to-adjust ( score-difference / range-of-scores )]
; Records the color and name of the house that is winning the game (updates as new games get played)
let bh-color [ my-color ] of best-house
let bh-house-name [ name ] of best-house
; Identifies the patchset that represents the territory of the winning house
let best-house-territory land-patches with [ house-color = bh-color ]
; A territory expands only if there is a range of throne scores and someone is winning the game...
if percent-to-adjust > 0 and best-house-territory != nobody [
ask best-house-territory [ update-borders ] ; this results in some patches having 'border?' set to true
let border-patches land-patches with [ border? = true ] ; Identifies the patches along the border that can be taken over
; Adjust territory by the percent to adjust multiplied by the winner's population density
let best-house-population count humans with [ color = bh-color ]
let pop-density ( best-house-population / count best-house-territory )
let number-to-adjust precision ( percent-to-adjust * pop-density * 10000 ) 0
ifelse number-to-adjust > count border-patches [
; Use the code below if more land is taken over than the number of border patches (e.g., if the border is at a bottleneck)
while [ number-to-adjust > 0 ][
; first, this part recalculates the boder patches to break the loop if there are no more
set best-house-territory land-patches with [ house-color = bh-color ] ; Patches of the winning house
ask land-patches [ set border? false ] ; Resets the borders
ask best-house-territory [ update-borders ] ; The winning patches identify their bordering patches
set border-patches land-patches with [ border? = true ] ; The border-patches patchset gets recalculated
if ( count border-patches ) < 1 [ ; If there are no more border patches, there cannot be more advance
set number-to-adjust 0
]
; then if there are still border patches, they change to the winning house
ifelse number-to-adjust > ( count border-patches )[
ask border-patches [
set house-color bh-color
set house bh-house-name
]
set number-to-adjust number-to-adjust - ( count border-patches ) ; updates the number to adjust
][ ; in case less patches need to be changed than are in the list border patches - only some are changed
ask n-of number-to-adjust border-patches [
set house-color bh-color
set house bh-house-name
]
set number-to-adjust 0 ; and update the number to adjust to reflect the fact that all have changed
] ; closes the "else" part of the ifelse statement
] ; closes the while loop
][ ; closes the "if" part of the ifelse number-to-adjust > count ... statement
; The code below is for when there are as or more border patches than what will be taken over
ask n-of number-to-adjust border-patches [
set house-color bh-color
set house bh-house-name
]
; the code below is to prevent the formation of islands of the wrong color
ask border-patches [
let color-score 0
ask neighbors [
if [ house-color ] of self != [ house-color ] of myself [
set color-score color-score + 1 ; all neighbors of different colors add 1 to this variable
]
]
if color-score > 4 [ ; if the patch is surrounded by other territories...
set house-color bh-color ; ...it takes the color and house of the winner
set house bh-house-name
]
]
]
] ; closes the main if statement
ask land-patches [ set border? false ] ; Resets the borders for next game
change-islands bh-color bh-house-name ; Change the allegiance of island patches
; Cities that are on patches that changed color also change color (they have been taken)
ask cities [ set color house-color ]
end
to adjust-territory ; observer procedure
let undefeated-houses houses with [ defeated? = false ]
let total-houses count undefeated-houses
let total-score sum [ throne-score ] of undefeated-houses
set average-household-strength ( total-score / total-houses )
let best-house one-of undefeated-houses with-max [ throne-score ]
let worst-house one-of undefeated-houses with-min [ throne-score ]
let max-score [ throne-score ] of best-house
let min-score [ throne-score ] of worst-house
let range-of-scores abs ( max-score - min-score )
let score-difference ( max-score - average-household-strength )
let percent-to-adjust 0
if range-of-scores > 0 [ set percent-to-adjust ( score-difference / range-of-scores )]
let bh-color [ my-color ] of best-house
let bh-house-name [ name ] of best-house
let best-house-territory land-patches with [ house-color = bh-color ]
if percent-to-adjust > 0 and best-house-territory != nobody [
ask best-house-territory [ update-borders ]
let border-patches land-patches with [ border? = true ]
let best-house-population count humans with [ color = bh-color ]
let pop-density ( best-house-population / count best-house-territory )
let number-to-adjust precision ( percent-to-adjust * pop-density * 10000 ) 0
ifelse number-to-adjust > count border-patches [
while [ number-to-adjust > 0 ][
set best-house-territory land-patches with [ house-color = bh-color ]
ask land-patches [ set border? false ]
ask best-house-territory [ update-borders ]
set border-patches land-patches with [ border? = true ]
if ( count border-patches ) < 1 [
set number-to-adjust 0
]
ifelse number-to-adjust > ( count border-patches )[
ask border-patches [
set house-color bh-color
set house bh-house-name
]
set number-to-adjust number-to-adjust - ( count border-patches )
][
ask n-of number-to-adjust border-patches [
set house-color bh-color
set house bh-house-name
]
set number-to-adjust 0
]
]
][
ask n-of number-to-adjust border-patches [
set house-color bh-color
set house bh-house-name
]
ask border-patches [
let color-score 0
ask neighbors [
if [ house-color ] of self != [ house-color ] of myself [
set color-score color-score + 1
]
]
if color-score > 4 [
set house-color bh-color
set house bh-house-name
]
]
]
]
ask land-patches [ set border? false ]
change-islands bh-color bh-house-name
ask cities [ set color house-color ]
end
;;; PATCHES PROCEDURE ;;;
to update-borders
let my-neighbors neighbors with [ land? = true and house-color != 0 ] ; identifies the land patches next to the asking patch
let my-house-color house-color ; identifies the color of the patch calling this procedur
ask my-neighbors [ ; this identifies the patches nearby that are from a different house
ifelse ( house-color != my-house-color )[ ; the patches that are not the same house become borders
set border? true
][
set border? false
]
]
end
;;; PATCHES PROCEDURE ;;;
to update-borders
let my-neighbors neighbors with [ land? = true and house-color != 0 ]
let my-house-color house-color
ask my-neighbors [
ifelse ( house-color != my-house-color )[
set border? true
][
set border? false
]
]
end
;;; PATCHES PROCEDURE ;;;
to change-islands [ bh-color bh-house-name ]
let tyrell-patches patches with [ house-color = 57 ]
if count tyrell-patches < 23 [ ; Tyrells have 22 patches of island, so when the size of their territory...
ask tyrell-patches [ ; ... reaches 22, it means only islands are left and they need to turn.
set house-color bh-color
set house bh-house-name
]
]
let martell-patches patches with [ house-color = 25 ]
if count martell-patches < 63 [ ; Martells have 62 patches of island, so when the size of their territory...
ask martell-patches [ ; ... reaches 62, it means only islands are left and they need to turn.
set house-color bh-color
set house bh-house-name
]
]
let baratheon-patches patches with [ house-color = 45 ]
if count baratheon-patches < 30 [ ; Baratheon have 29 patches of island
ask baratheon-patches [
set house-color bh-color
set house bh-house-name
]
]
let targaryen-patches patches with [ house-color = 13 ]
if count targaryen-patches < 8 [ ; Targaryens have 7 patches of island
ask targaryen-patches [
set house-color bh-color
set house bh-house-name
]
]
let arryn-patches patches with [ house-color = 97 ]
if count arryn-patches < 20 [ ; Arryns have 19 patches of island
ask arryn-patches [
set house-color bh-color
set house bh-house-name
]
]
let stark-patches patches with [ house-color = 4 ]
if count stark-patches < 94 [ ; Starks have 93 patches of island
ask stark-patches [
set house-color bh-color
set house bh-house-name
]
]
end
;;; PATCHES PROCEDURE ;;;
to change-islands [ bh-color bh-house-name ]
let tyrell-patches patches with [ house-color = 57 ]
if count tyrell-patches < 23 [
ask tyrell-patches [
set house-color bh-color
set house bh-house-name
]
]
let martell-patches patches with [ house-color = 25 ]
if count martell-patches < 63 [
ask martell-patches [
set house-color bh-color
set house bh-house-name
]
]
let baratheon-patches patches with [ house-color = 45 ]
if count baratheon-patches < 30 [
ask baratheon-patches [
set house-color bh-color
set house bh-house-name
]
]
let targaryen-patches patches with [ house-color = 13 ]
if count targaryen-patches < 8 [
ask targaryen-patches [
set house-color bh-color
set house bh-house-name
]
]
let arryn-patches patches with [ house-color = 97 ]
if count arryn-patches < 20 [
ask arryn-patches [
set house-color bh-color
set house bh-house-name
]
]
let stark-patches patches with [ house-color = 4 ]
if count stark-patches < 94 [
ask stark-patches [
set house-color bh-color
set house bh-house-name
]
]
end
; then the houses that are still undefeated fight
ask houses with [ defeated? = false ][
fight
]
; calls the adjust-territory procedure so that the winning house expands its territory
adjust-territory
ask houses with [ defeated? = false ][
fight
]
adjust-territory
8. Visualize the results
Now that you have added all this code, the territories should change size in the background, but what if we want to see those in the World window?
​
This part is pretty simple now that you've done most of the grunt work. On the Interface, create a switch called display-house-ownership?.
​
Then, update the go procedure by adding a few lines to change the color of the patches based on the switch position.
if conflict? [ ; if conflict? switch is ON (same as "if conflict? = true"), houses will fight using the prisoner's dilemma
update-players ; update the list of possible players
if length players > 1 [ ; the houses fight only if there are more than one house left
houses-fight-for-territory
]
]
if display-house-ownership? [
ask land-patches [ ; Only the land patches
set pcolor house-color ; Change their colors to the house that just conquered it
]
]
if conflict? [
update-players
if length players > 1 [
houses-fight-for-territory
]
]
if display-house-ownership? [
ask land-patches [
set pcolor house-color
]
]
9. Why are all the sheep dying?
Visualizing the territory changes that occur because of the Prisoner's dilemma game is fun, but you may notice that, as soon as you set the patch colors to their houses, sheep health plummets.
​
This is because the ways in which sheep and humans feed on grass is linked to the color of the patches. Sheep will only get resources from a green patch. Therefore, if a patch with grass (green) becomes red, sheep will not know that it has grass, and all sheep will starve.
​
This means that we need to change the ways in which sheep and humans interact with grassy patches.
​
Again, this shows that adding components to a model often leads to additional changes that are not directly related to the new components.
​
The first step to fix this problem is to create a new patch variable called resources. This will be the variable that sheep and humans will use to know if they can get food from patches. Then, change the setup procedure so that grassy patches get resources.
​
Then, change the eat-grass procedure so that sheep recognizes patches with resources even when they are colored by house (remove the code in red and add the code in blue in the lines below). Similarly, update the grow-grass procedure so that color is no longer used to determine growth.
​
Finally, for simplicity, change the humans-eat procedure so that they call the eat-grass procedure. It's simpler this way as it avoids copying the same code over and over (which is bad coding practice).
patches-own [
countdown ; used to trigger grass regrowth
land? ; boolean that identifies is a cell is land
wall? ; boolean that identifies if the cell overlaps the wall (and thus is part of the wall)
house ; identifies which house owns the cell
house-color ; to show the extent of each house's territory
road? ; identify if the patch is part of a road
border? ; identify if a patch is at the border between two house territories
resources ; records how much resources there are on patch
]
patches-own [
countdown
land?
wall?
house
house-color
road?
border?
resources
]
ask land-patches [ ; ask only land patches to do what's between the square brackets
ifelse road? = true [
set pcolor black ; roads are black and do not have resources
][
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 resources sheep-gain-from-food ; each grassy patch starts with enough resources to feed one sheep
][
set countdown random grass-regrowth-time ; initialize grass regrowth clocks randomly for brown patches
set resources 0 ; brown patches have no resources
]
]
]
ask land-patches [
ifelse road? = true [
set pcolor black
][
set pcolor one-of [ green brown ]
ifelse pcolor = green [
set countdown grass-regrowth-time
set resources sheep-gain-from-food
][
set countdown random grass-regrowth-time
set resources 0
]
]
]
to grow-grass ; patch procedure
; countdown on brown patches: if you reach 0, grow some grass
if pcolor = brown [
if resources = 0 [ ; if there are no more resources
ifelse countdown <= 0 [ ; and the countdown reached 0
set pcolor green
set resources sheep-gain-from-food ; regain resources
set countdown grass-regrowth-time
][
set countdown countdown - 1
]
]
end
to grow-grass
if pcolor = brown [
if resources = 0 [
ifelse countdown <= 0 [
set pcolor green
set resources sheep-gain-from-food
set countdown grass-regrowth-time
][
set countdown countdown - 1
]
]
end
to go
[ ... ]
​
ask land-patches [ grow-grass ]
if conflict? [ ; if conflict? switch is ON (same as "if conflict? = true"), houses will fight using the prisoner's dilemma
update-players ; update the list of possible players
if length players > 1 [ ; the houses fight only if there are more than one house left
houses-fight-for-territory
]
]
ifelse display-house-ownership? [
ask land-patches [ ; Only the land patches
set pcolor house-color ; Change their colors to the house that just conquered it
]
][
ask land-patches [
ifelse resources = 0 [
set pcolor brown ; depleted patches are brown
][
set pcolor green ; patches with grass are green
]
]
]
to go
[ ... ]
​
ask land-patches [ grow-grass ]
if conflict? [
update-players
if length players > 1 [
houses-fight-for-territory
]
]
ifelse display-house-ownership? [
ask land-patches [
set pcolor house-color
]
][
ask land-patches [
ifelse resources = 0 [
set pcolor brown
][
set pcolor green
]
]
]
to humans-eat
[ ... ]
​
][ ; If not eating a sheep, still getting some nutrients from cultivated grass (wheat?)
if pcolor = green [
set pcolor brown
set energy energy + (sheep-gain-from-food / 4) ; But still not as good as eating a sheep
]
eat-grass ; calls the eat-grass procedure
]
end
to humans-eat
[ ... ]
​
][
if pcolor = green [
set pcolor brown
set energy energy + (sheep-gain-from-food / 4) ; But still not as good as eating a sheep
]
eat-grass
]
end
to eat-grass ; sheep and human procedure
; sheep and human eat grass
if pcolor = green [
if resources > 0 [ ; the sheep (or human) asks if the patch here has resources
set pcolor brown
set energy energy + resources ; if so, it gains energy by eating
set resources 0 ; depletes the patch
]
end
to eat-grass
if pcolor = green [
if resources > 0 [
set pcolor brown
set energy energy + resources
set resources 0
]
end
10. You fixed it!
Congratulations on completing the hardest part in making your own Game of Thrones model! Now, you have houses fighting over territory and taking each other's land.
​
If you run the model multiple times, can you tell which house wins the most? Is it a house that cooperates often or is it one that defects? Does it vary a lot? How does that change based on the battle-strategy?
​
If you want to see the finished model for this step, download it here​.
​
In the next step, we will introduce a small variation in the population distribution in each kingdom to better reflect the patterns seen in the ASOIAF books. See you there!