Step 8. Add dragons

1. Dragons in Dragonstone

We assume that this is the moment most of you will have been waiting for. Here, you will introduce dragons to your model. There will be only three dragons, who will start their journey near Dragonstone (of course, because this is where Daenerys lands first in Westeros). Dragons will fly fast and will kill the whitewalkers they encounter. However, as they are wild animals, they will sometimes kill and eat people too... a dragon's gotta eat, after all.

The first step, as often in this model, is to create a new breed of agents called dragons.

Then, create a setup-dragons procedure that will create Drogon, Viserion, and Rhaegal at Dragonstone. You can import the dragon shape from this model. Do not yet call that procedure in setup however, as the dragons' arrival needs to be timed.

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 [ dragons dragon ]  ; dragons can kill whitewalkers fast

breed [ sheep a-sheep ] 

breed [ wolves wolf ]

breed [ humans human ] 

breed [ cities city ]  

breed [ houses a-house ] 

breed [ dragons dragon ] 

to setup-dragons   ; observer procedure

  ; dragons show up at Dragonstone

  ask one-of cities with [ city-name = "Dragonstone" ][

    hatch-dragons 3 [

      set size 15   ; they are big

      set shape "dragon" 

    ]

  ]

  

end

to setup-dragons   

 

  ask one-of cities with [ city-name = "Dragonstone" ][

    hatch-dragons 3 [

      set size 15   

      set shape "dragon" 

    ]

  ]

  

end

Input_DragonsDelay.png

2. Timing the arrival

At the end of the published ASOIAF books, the dragons have not yet reached Westeros, so here we use the show's timing to determine when the dragons will appear in the model. 

In the show, Sansa tells Jon that a white raven arrived in Winterfell during the last episode of Season 6. At the end of that episode, Daenerys sails towards Westeros, but she has not yet landed when the season ends. If we assume that the shows' chronology is correct (this is not Westworld, after all), we should assume that dragons will arrive in Westeros after winter does (also, in the books, whitewalkers are very active from the start of the story, so...). But how soon after is your choice.

To have a flexible arrival, create an input called dragons-delay in the Interface that will take a number (make sure to change the "Type" to "Number" because the default is "Text"). 

Then, create a new global variable that will represent a counter. That counter will start when winter is here and will increase by 1 at every tick. When it reaches the value entered in dragons-delay, the dragons will hatch. 

Using such an input and counter will allow you to test the model and see which delay values leads to the fastest killing of whitewalkers.

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

  season   ; record the current season

  dragons-counter   ; will time the dragons' arrival after winter comes

]

globals [

  max-sheep 

  land-patches 

  players  

  average-household-strength   

  season  

  dragons-counter  

]

to go 

  [ ... ]

  if season = "winter" [

    set dragons-counter dragons-counter + 1   ; adds 1 to the counter at each tick

    if dragons-counter = dragons-delay [   ; if the counter has reached the number in the input...

      setup-dragons   ; ... dragons arrive at Dragonstone

    ]

    winter-advance   ; during winter, whitewalkers move and kill

  ]

to go 

  [ ... ]

  if season = "winter" [

    set dragons-counter dragons-counter + 1  

    if dragons-counter = dragons-delay [  

      setup-dragons 

    ]

    winter-advance 

  ]

3. Let them fly

Give your model a try! To make things happen quickly, try it with small numbers for both season-change-rate and dragons-delay. Can you see dragons pop-up on top of Dragonstone?

Now it's time to let them move. As dragons fly, they are much faster than humans and will move 10x as fast as them. To do that, you will use the repeat primitive, which repeats any code a given number of times.

Dragons will be able to roam over the sea a little bit, but when they go too far (>10 patches from land), they will have to turn around and go back to land.

Create a new move-dragons procedure and call it within go. Try your code. Aren't the dragons majestic?

Dragons.png

to move-dragons   ; observer procedure

  

  ask dragons [

    repeat 10 [   ; this will repeat 10 times everything that is between the brackets following it

      rt random 30   ; wiggle a lot

      lt random 30

      ifelse patch-ahead 1 != nobody [   ; if the patch ahead is something (land or water)

        let land-patch-nearby land-patches in-radius 10   ; always keep land patches in sight

        if not any? land-patch-nearby [   ; if a land patch is not in sight anymore (went too far)...

          face one-of land-patches with-min [ distance myself ]   ; the dragon turns towards the closest land patch

        ]

        fd 1   ; then the dragon moves ahead by 1

      ][ 

        rt 180   ; this is if the dragon is at the edge of the window, it turns around

        fd 1    ; and moves by 1

      ]

    ]

  ]

  

end

to move-dragons   

  

  ask dragons [

    repeat 10 [  

      rt random 30 

      lt random 30

      ifelse patch-ahead 1 != nobody [  

        let land-patch-nearby land-patches in-radius 10  

        if not any? land-patch-nearby [ 

          face one-of land-patches with-min [ distance myself ] 

        ]

        fd 1  

      ][ 

        rt 180  

        fd 1   

      ]

    ]

  ]

  

end

to go

  [ ... ]

  if season = "winter" [

    set dragons-counter dragons-counter + 1   ; adds 1 to the counter at each tick

    if dragons-counter = dragons-delay [   ; if the counter has reached the number in the input...

      setup-dragons   ; ... dragons arrive at Dragonstone

    ]

    winter-advance   ; during winter, whitewalkers move and kill

    if any? dragons [   ; if it is winter and dragons are here, they move

      move-dragons

    ]

  ]

to go

  [ ... ]

  if season = "winter" [

    set dragons-counter dragons-counter + 1 

    if dragons-counter = dragons-delay [  

      setup-dragons   

    ]

    winter-advance 

    if any? dragons [ 

      move-dragons

    ]

  ]

4. Dracaris!

You are almost done! Now that the dragons are flying around, they need to kill any whitewalkers they see within a certain radius as well as all sheep and ~10% of the humans they directly fly over. 

Create a new procedure called dragons-kill. In it, the dragons start by checking if there are any whitewalkers within a radius of 4. If there are, they all die. Then, it moves to sheep and humans. If there are sheep, one of them gets eaten. If there are humans, one human has a 10% chance of getting eaten.

Call that procedure within move-dragons.

to dragons-kill   ; dragon procedure

  

  let whitewalker-prey whitewalkers in-radius 4  ; dragons can hunt whitewalkers at wide expanses

  if any? whitewalker-prey [

    show "Dracaris!!!"   ; if there is a whitewalker around, they burn it/them

    ask whitewalker-prey [ die ]

  ]

  

  let prey one-of sheep-here   ; if there is one sheep on the same patch, it eats it

  if prey != nobody [

    ask prey [ die ]

  ]

  

  let human-prey one-of humans-here   ; if there is one human on the same patch...

  if human-prey != nobody and random 100 < 10 [   ; ... ~10% of the time, the human will be gobbled up

    ask human-prey [ die ]

  ]

  

end

to dragons-kill  

  

  let whitewalker-prey whitewalkers in-radius 4  

  if any? whitewalker-prey [

    show "Dracaris!!!"  

    ask whitewalker-prey [ die ]

  ]

  

  let prey one-of sheep-here   

  if prey != nobody [

    ask prey [ die ]

  ]

  

  let human-prey one-of humans-here  

  if human-prey != nobody and random 100 < 10 [  

    ask human-prey [ die ]

  ]

  

end

to move-dragons   ; observer procedure

  

  ask dragons [

    repeat 10 [   ; this will repeat 10 times everything that is between the brackets following it

      rt random 30   ; wiggle a lot

      lt random 30

      ifelse patch-ahead 1 != nobody [   ; if the patch ahead is something (land or water)

        let land-patch-nearby land-patches in-radius 10   ; always keep land patches in sight

        if not any? land-patch-nearby [   ; if a land patch is not in sight anymore (went too far)...

          face one-of land-patches with-min [ distance myself ]   ; the dragon turns towards the closest land patch

        ]

        fd 1   ; then the dragon moves ahead by 1

      ][ 

        rt 180   ; this is if the dragon is at the edge of the window, it turns around

        fd 1    ; and moves by 1

      ]

      dragons-kill   ; after every move, the dragon can kill whitewalkers, sheep, and some humans

    ]

  ]

  

end

to move-dragons 

  

  ask dragons [

    repeat 10 [  

      rt random 30 

      lt random 30

      ifelse patch-ahead 1 != nobody [ 

        let land-patch-nearby land-patches in-radius 10  

        if not any? land-patch-nearby [  

          face one-of land-patches with-min [ distance myself ]  

        ]

        fd 1   

      ][ 

        rt 180 

        fd 1   

      ]

      dragons-kill  

    ]

  ]

  

end

5. Is it summer yet?

In the dragons-kill procedure, you may have noticed that we use two different primitives to ask if there is/are any whitewalkers or humans: if any? whitewalker-prey and if prey != nobody. Why is that?

If any? refers to an agentset that could have one or more agents.  Here, the whitewalkers-prey variable represents an agentset of all the whitewalkers in a certain radius. If there are a few whitewalkers around, this agentset will represent multiple agents; however, if there are no whitewalkers around, this will still represent an agentset, but it will be empty (Agentset, 0 agents). As it still represents something (an agentset), it is not equal to nobody. Therefore, you cannot use if != nobody with an agents, because it will never be true. 

On the other hand, prey is meant to represent a single agent, as it is called by one-of. If there are no sheep here, this variable will represent nobody. Any? cannot be called on something that represents nobody, therefore, you need to use if != nobody instead.

Let's go back to the model and add the last finishing touch. Right now, when the Whitewalkers win, the model stops and a message appears telling us that the Night King has won, remember? Let's add a similar message for when whitewalkers are defeated.

to go

  ; stop the model if there are no more wolves, sheep or humans

  let living-things ( turtle-set wolves sheep humans )

 

  if not any? living-things [

    user-message "The Night King has won!"

    stop

  ]

  ; if all whitewalkers die, it becomes spring and resources grow back

  if season = "winter" and count whitewalkers = 0 [

    set season "spring"   ; finally!!

    ask patches with [ snow? ][

      set snow? false   ; snow melts and resources grow back (just for visuals, as the model stops)

      ifelse resources = 0 [

        set pcolor brown 

      ][ 

        set pcolor green 

      ]

    ]

    user-message "The Night King has been defeated! Summer is back."

    stop 

  ]

to go

  

  let living-things ( turtle-set wolves sheep humans )

 

  if not any? living-things [

    user-message "The Night King has won!"

    stop

  ]

 

  if season = "winter" and count whitewalkers = 0 [

    set season "spring"  

    ask patches with [ snow? ][

      set snow? false   

      ifelse resources = 0 [

        set pcolor brown 

      ][ 

        set pcolor green 

      ]

    ]

    user-message "The Night King has been defeated! Summer is back."

    stop 

  ]

Final.png

6. Your turn!

Congratulations on building your own Game of Thrones ABM. Models are simplifications of systems, and thus there are things we did not include in this model. On the other hand, there are things we kept that could probably be removed. It is now your turn to change this model to make it what you want.

Ideas of things we thought of implementing but didn't:

- A Petyr Baelish character who travels from city to city. The house he visits always defects at the prisoner's dilemma.

- An Arya character who just kills people from the houses that defeats the Stark.

- Different killing abilities for dragons. They could have different colors (green, beige, black) and kill whitewalkers in different radius (Drogon would kill further as he is bigger).

- Tweaking the prisoner's dilemma so that houses only play against their immediate neighbors.

What about you? Any idea on how we could improve this model even more?

It has been a pleasure building this model from "almost" scratch. We hope you had fun following through the instructions too. You can find the finalized model here

Thank you! 

Claudine and Sean