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.

Conflict.png
battleStrategy.png
chance-of-cooperation.png

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.

Monitor.png

;;; 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.

SwitchHouse.png

  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   

    ]

  ]

NoSheep.png

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!