Simulate a Virus
Laurence Molloy, Creative Smart Things
In recognition of the economic impact of the Coronavirus pandemic, this learning resource has been made available on a Pay What You Want basis.
If your kids enjoy this project material and you can afford to do so, then please show your support with a donation. The amount that you donate is entirely up to you. Any amount that you can give, however small, is greatly appreciated.
If you cannot afford to donate, then please do not feel obliged to do so. Free is also fine with me. All I ask is that you recommend these projects to others and leave a review.
In this project you will write a program using Scratch 3 that simulates the spread of a virus, allowing you to examine the effects of social distancing on the rate and extent of infection spread across a virtual population.
As the coronavirus pandemic spreads across the globe, governments are attempting to delay its spread among their populations by announcing social distancing measures. So, what exactly is social distancing?
Definition: ”social distancing“ is the practice of protecting the health of a population by banning large gatherings of people (such as sports events and pop concerts) and requiring everyone to maintain a minimum distance from each other at all times. This reduces the risk of passing on a virus which in turn slows down the speed with which a contagious illness can spread through the population.
How does social distancing work in practice? Let’s illustrate this with a diagram.
The curve on the right above shows the effect of slowing down the spread of infection. The time period over which the virus spreads is lengthened. This lowers the maximum number of infected people at any point in time which reduces the maximum rate of hospital admissions to a level that the health system can better manage. In the diagram above, this is represented by the highest points on the curves (# of cases) and the horizontal line (healthcare system capacity).
This model presumes that everyone will follow the rules imposed upon them by the government. However, not everyone follows rules. How effective would social distancing be if 25% of the population were to ignore the government directive to maintain a safe distance? What if social disobedience is as high as 50%?
In this project we will answer these questions by building a simulation that unleashes a virus upon a virtual population, observes the spread of that virus over a period of time and then generates an infection curve, just like the ones above.
Definition: A ”simulation“ is a computer program that models real system behaviours without having to interact with the physical system. This allows us to learn about costly or dangerous situations in a completely risk-free way and control important aspects of the system that would not be easy to control in real life.
In our case, the system is a human population and the behaviour we wish to model is the spread of a virus among that population. The system aspect that we will be controlling is the level of civil obedience.
- Why would it be neither possible nor desirable to perform our virus experiments with a real population?
- Can you think of other situations where it would be useful to create a simulation to learn about the behaviour of a system?
Okay. So let’s get down to business and create our simulation…
Create a Person Sprite
Start a new Scratch project by opening https://scratch.mit.edu/projects/editor in a browser. Every new Scratch project starts with the cat sprite. We won’t be using this so click on the dustbin icon in the top right corner of the sprite in the sprite area to delete it.
Let’s now create a circular sprite that will represent the people in our population.
- Click on the new sprite button in the sprite area to create a new sprite. An options panel will slide up from behind the button.
- Select the paint option to draw your own sprite. This will open the paint tool.
- Click on the zoom button in the bottom right corner of the paint tool to zoom in on the drawing area so you can clearly see the background checkerboard squares.
- Select the ellipse tool. Move to the centre of the drawing area. Click and hold the mouse while dragging the pointer to create a circle that is approximately 3 squares high and 3 squares wide. Once created, you can adjust its size by clicking and dragging on the edges of the square border around the ellipse object created.
- Click on the arrow next to the fill color tool. In the display that appears, adjust the color, saturation and brightness until you get a sky blue colour. This will be our healthy person colour.
Create a Town with a Population of Healthy People
Let’s create a population of 100 healthy people (blue dots) in addition to our original person sprite and distribute these people around our town (the Scratch stage).
The code in this section should be created for your person sprite.
- Define a function called setup *. This is where we will set up our initial conditions.
- Set the start location of our first person to the centre of the screen ( go to x:0 y:0 ).
- To create a population of 100 people, we will clone our person sprite 100 times. To do this, place a create a clone of myself instruction inside a repeat 100 loop.
- To position our population randomly across our town create a when I start as a clone block of code and attach a go to random position block within it.
- To generate the population when the program is run, call the setup function when the green flag is clicked .
* if you’re not sure how to create a function, see the parental guidance notes at the end of this project guide.
Test your code
Click on the green flag to run the code. If you have followed the instructions above you will see a population of healthy people (blue dots) appear on the stage.
Let’s also test the randomness of our initial population distribution. Re-run the code a number of times. Does the pattern of dots change with every run?
Allow Your Population To Move Freely Around
Let’s now simulate our population going about its daily business. We can do this by modelling the movement of each person under normal conditions as a random walk.
Definition: A “random walk“ is a pattern of movement that is similar to wandering aimlessly around an area. Scientists use random walks to model the behaviour of many natural processes such as the search path of a foraging animal or the movement of molecules in liquids and gases (aka Brownian Motion).
- Create a sprite-specific variable called stay-at-home? We will use this variable to control whether each person will be allowed to move about the town. Every person will be given its own independent copy of this variable.
- For now, we will allow the entire population to move around freely. When each clone (person) is created, set the stay-at-home? variable to false.
- In the when green flag clicked block, immediately after the setup, repeat 480 time steps. Send a broadcast clock-tick message with each time step.
- Define a function called random walk that takes 3 steps in a random direction. To do this, turn a random amount (within +/- 30 degrees) and then move forward 3 steps . If you hit the edge of the screen, bounce back.
- For each person, when it receives the clock-tick message , if stay at home? is false (the person is allowed to move) then perform a single random walk step.
Test your code
Click on the green flag to run the code. If you have followed the instructions above you will see your healthy population moving around the stage. If your population does not move about the stage, carefully check your spelling for “false” in steps 2 & 5.
Impose Social Distancing Measures On Your Population
We will now impose a rule telling the population that they must stay at home. We also want to model the fact that not everyone will follow this rule and have control over the level of civil obedience.
- Create a global stay-at-home-% variable. “global” is another way of saying that it is shared for all sprites. This represents our level of civil obedience. Tick the checkbox to the left of the variable to make it visible on the stage.
Definition: A “global“ variable is a variable that is shared by all sprites. In Scratch, we say that this variable is for all sprites. In the case of the stay-at-home-% variable, it needs to be global because it applies to the population as a whole, not the people individually.
We want the user to be able to easily control the level of civil obedience by adjusting the stay-at-home-% value.
- Double click on the visible stay-at-home-% variable in the top left corner of the stage to change it to large format. Double click on it again to change it to a user-controllable slider.
Let’s now write some code that determines whether or not each person in our population stays at home (remains static) or not (moves about the stage) based on the level of civil obedience set by the user.
- Within the setup function, show the stay-at-home-% variable. This ensures that it remains visible on the stage.
- Let’s leave our original person sprite to move around freely. Within the setup function, set the stay at home? variable to false.
- For each member of the population (clone), we want to determine whether that person will move based on our selected level of civil obedience ( stay-at-home-% ). Within the when I start as a clone block, replace the previous set stay at home? to false block with the following code logic:
- Pick a random number between 0 and 99. Let’s call this number N.
- IF N < stay-at-home-%
- THEN this person is obedient – set stay at home? to true.
- ELSE this person is disobedient – set stay at home? to false.
Test your code
Set the slider value to 100% and click on the green flag to run your code. If you have followed the instructions above you will see your healthy population appear with only a single person moving around the stage (the original person sprite).
Now set the slider value to around 50% and re-run the code. What percentage of the population do you see moving around? Re-run the code using a selection of slider values to see how it affects the number of people moving around the town.
Define the Parameters of
Let’s now define some parameters for our simulation. For instance, the population will start off healthy and the virus has key characteristics that we need to model such as how long a person takes to recover from the virus once infected.
A warning about variable types
This section asks you to create a lot of variables. Some are for all sprites and others are for this sprite only. The type of variable that you create is very important. Creating the wrong type of variable can prevent your code from working as intended. When creating variables, please check very carefully that you are creating the type that is being asked for as it is not possible to change the variable type once it has been created.
- Create a sick variable for all sprites. This records the number of sick people in the population. Everyone is healthy to begin with. In the setup function, set sick to 0 .
- Create a time to recover variable for all sprites. This defines how long it takes for a person to recover from the virus once they become sick. Let’s define the recovery period to be 100 ticks. In the setup function, set time to recover to 100 .
- For each person, create a health variable for this sprite only. In the beginning, everyone is healthy so set health to “healthy” . When someone catches the virus we will record this fact by changing this variable to ”sick” (see step 5).
- Once someone has caught the virus we need to keep track of how many days that person has been carrying the virus for so that we know when he/she is due to recover. Create a time sick variable for this sprite only. We’ll initialise this value whenever a person becomes infected (see step 5).
- Define an infect function. We will call this function whenever someone new gets infected. Within this function, create the following code logic:
- Set color effect to 50 – This visibly identifies the person as sick by turning the dot pink.
- set health to “sick” – This logically identifies the person as sick by changing that person’s health status from “healthy” to “sick”.
- Change sick by 1 – This increases the population’s sick count by 1.
- Set time sick to 0 – This starts the person’s sickness clock counting from 0.
- Let’s unleash the virus on the population by infecting our original person sprite. In the setup function, after the population has been created, call the infect function.
- The only variable that we want to be visible on the stage is the stay-at-home-% variable. Click on the Variables section of the menu and untick all the variables except for the stay-at-home-% variable.
Test your code
Click on the green flag to run your code. If you have followed the instructions above you will see your healthy population appear as blue dots with only a single person in pink, the original person sprite which we have infected.
Define the Rules of Infection
At any given point in time the health of each member of our population will be one of “healthy”, “sick” or “recovered”. The health of a person can change according to the following rules:
- A healthy person becomes sick when he/she comes into contact with a sick person.
- A sick person becomes recovered when he/she has been sick for 100 ticks.
- A recovered person cannot be re-infected as that person has developed immunity.
This set of rules can be represented in a diagram, as shown below.
In this diagram the health states are shown as circles. The ways in which a person’s health can change are called state transitions. These are shown as arrows connecting two states. The conditions required for each state transition to occur are written next to each arrow.
Definition: In computer science, a diagram which describes the behaviour of a system or process as a set of connected states is known as a state diagram. Can you think of any other real life processes that you can represent in the form of a state diagram?
We have already defined what happens in our simulation when a healthy person becomes sick. That’s the infect function that we wrote earlier and used to infect the first person. Let’s now create a recover function to define what should happen when a person recovers from the virus. We will call this function whenever someone has been sick for 100 ticks. Within this function, create the following code logic:
- set color effect to 140
This visibly identifies the person as recovered by turning the dot green.
- set health to “recovered”
This logically identifies the person as recovered by changing that person’s health status from “sick” to “recovered”.
- change sick by -1
This reduces the population’s sick count by 1.
Let’s now code up the conditions for the transitions from healthy to sick and from sick to recovered in our state diagram. At each time step we will check on our population to determine if any healthy people should become sick and any sick people should recover.
- Define a check healthy function to check on the healthy population.
Our rule for infection states that anyone healthy that comes into contact with a sick person will become sick. We test for that with a touching colour test. If a healthy person is touching a sick person we call the infect function to change that person’s health status from healthy to sick.
To select the correct colour for the touching colour test, click on the green arrow and let the simulation run to completion. When your population stops moving
- click on the color in the touching colour block
- click on the color selector tool in the display window that appears above
- move over the infected person on the stage. The area around your mouse will be magnified. When the border around the magnified region turns pink click on the mouse button. The color in the touching colour block will now turn pink to match the color of your infected person.
- Define a check sick function to check on the sick population.
Our rule for recovery states that a sick person will recover after being sick for 100 ticks. This is the time to recover value that we defined in the setup function.
- Every time we check a sick person, we increase its time to sick value by 1 tick.
- When time sick > time to recover we call the recover function to make that person well again.
healthy vs recovered: People who have recovered from the virus have built up immunity to it. If we returned people back to a healthy state after recovery, they could catch the virus for a second time. This is because our code logic does not treat healthy people as immune. To create immunity within our simulation we use a recovered health state for people who have both had the virus and recovered from it.
We need to repeat the health checks of our population every time the clock ticks so let’s add some code logic to the end of our when I receive clock tick block to do this.
- If the person’s health is healthy, call the check healthy function to determine if this person should become sick.
- If the person’s health is sick, call the check sick function to determine if this person should become recovered.
Test your code
Set the stay-at-home-% slider to 50% and click on the green flag to run your code. If you have followed the instructions above your population will appear and around half of them will move around. They will slowly turn pink as people come into contact with a sick person. Those that turn pink will eventually turn green as they recover.
If the code does not behave as described above, carefully check your spelling of “healthy” and “sick” everywhere you have used it (setting and checking variables). Also check that you have created your health variable for this sprite only.*
Plot The Infection Curve
The code we have written uses the sick variable to keep a record of the number of sick people in our population at any given time. Let’s show how the value stored in this variable changes over time in the form of a graph.
Definition: Graphs are a way of representing data in the form of a picture using lines, shapes and colours. Pictures are often easier to understand than numbers or words.
We’ll need to create a new sprite that will draw this graph.
- Click on the new sprite button in the sprite area to create a new sprite. An options panel will slide up from behind the button.
- Select the paint option to draw your own sprite. This will open the paint tool.
- We don’t need to create a costume for this sprite so just click on the code tab to switch from the paint tool to the code window.
Let’s write some code for this sprite that draws a line graph using the entire stage as our canvas. A line graph is a line that “joins the dots” of our measurement points. Our measurement points will be the total number of infected people at any given point in time.
The count of infected people (the sick variable) will determine the height of each measurement point on the stage ( y position ):
- the bottom of the stage (y = -180) = 0 people sick.
- the top of the stage (y = +180) = 100 people sick.
The time (in number of ticks) will determine the horizontal position of each measurement point on the stage ( x position ):
- the left edge of the stage (x = -240) = 0 ticks.
- the right edge of the stage (x = +240) = 480 ticks.
To draw a graph we need to use the pen. The blocks for this are not part of the core Scratch application. They belong to an extension package. Let’s add that extension.
- Click on the add extensions icon in the bottom left corner of the screen, below the blocks menu. This opens a window containing a number of extensions.
- Click on the pen extension. You will now be returned to the main screen with an extra set of pen-related blocks visible in your blocks palette.
We are now ready to start plotting the infection curve.
- when the green flag is clicked clear the graph and set up the pen in the bottom left corner of the screen, ready to start plotting data:
- start by hiding the pen sprite.
- erase all – this clears the screen of all previous pen drawings.
- pen up – this allows us to reposition the pen without drawing on the stage.
- go to -240 , -180 – this moves the pen to the bottom left corner of the stage.
- pen down – we are now ready to draw on the stage.
- With every tick of the clock we move the sprite to a new (x, y) measurement point that represents the latest sick count.
- the new x value is 1 more than the last one. x position = x position + 1.
- The new y value is y position = -180 + sick * 3.6.
In step 2b we are scaling our y value. Scaling takes the range of possible input values (the count of sick people, 0 < sick < 100) and maps this to the range of possible output values (the vertical position on the stage, -180 < y position < +180).
Challenge: Check that the scaling calculation in 2b above works by replacing sick with the values 0 and 100 and manually calculating y position . What values for y position do you get? Are they at the bottom and the top of the stage?
Run The Simulation
Let’s run the simulation to test our code. Click on the green arrow.
With the exception of the initial infected person, the population will start healthy (blue dots). Some of them will move about the screen according to the level of civil obedience that you have selected. As time progresses, the blue dots will change colour to pink as they come into contact with pink dots and become sick. After a period of time, pink dots will turn green as they recover.
As the simulation progresses to completion, the pen sprite will slowly draw a line across the screen, starting on the left and ending on the right. As the number of sick people grows, the height of the line will rise. As the number of sick people reduces (where the rate of recovery is faster than the rate of infection), the height of the line will fall.
An example run of this simulation with a 50% obedience rate set is shown below:
Re-run this simulation using a number of different levels of civil obedience by adjusting the stay-at-home-% slider value and re-running the code. What do you observe when you increase this value? What do you observe when you decrease it?
Well done! You’ve just created a basic virus simulator.
If you’re feeling adventurous, below are some suggestions for extensions to the code that you might like to attempt.
Recovery Time (Easy)
What impact does recovery time have on the spread of the virus?
- Turn the time to recover variable into a visible slider value on the stage that you can control and re-run the simulation using different values to see what effect it has.
Population Size (Easy)
What impact does population size have on the spread of the virus?
- Change the code to increase the population size and observe what happens for a given level of civil obedience and recovery time.
- What happens to the infection curve when more than 100 people become infected? Fix this by adjusting the scaling calculation for y position .
Chance of Infection (Intermediate)
What if contact with a sick person doesn’t always pass on an infection?
- Add an element of chance to your code that decides whether to infect a new person when it comes into contact with a sick person, based on a percentage value set.
Death Rate (Intermediate)
Some viruses are nothing more than irritations. Others can be more serious. What happens if a virus has a risk of death attached to it?
- Define a death rate variable as a percentage of sick people who die. After the recovery period, decide if a sick person dies or recovers based on your death rate . When a person dies, remove that person from the simulation.
- Create a second plotting sprite and write some code to display a graph of the count of dead people in your population over time.
Accelerated Death Rate (Difficult)
Examine what happens if the likelihood of death increases during periods when we have run out of hospital beds to treat the sick. For this challenge, it’s up to you to work out what you need to add or change in your code.
Parental Guidance Notes
This project can be attempted by children as young as 9 years old with some parental guidance. With this in mind, I have written some guidance notes for parents that address the most likely issues that can arise.
Instructions and supporting images
To make this project accessible to a younger audience, all written instructions are supported by images that illustrate actions and show completed code. Each instruction is numbered and the equivalent aspect of the accompanying image has been labelled identically. This makes it easy to relate individual actions & blocks of code in picture form to specific instructions.
Younger children are likely to rely more on the pictures. While it is possible to complete the project using the pictures alone, it can sometimes raise questions. If this happens it can be helpful to look for the relevant written instruction(s) and read them through with the child.
Adding to existing code blocks / creating new code blocks
Where the child is required to insert new code within an existing block of code, the full code block is shown in the image for context, with the code blocks they need to insert highlighted within red boxes.
Where it is necessary to create a completely new block of code, the code block is either entirely enclosed within a red box or contains no red boxes within it.
There are a number of functions to create in this project. Children who are not familiar with Scratch 3 may not know how to do that. The instructions below should help.
- Click on the My Blocks menu. The Make a Block button will appear on the right.
- Click on the Make a Block button to create a function block of your own.
- Type the name of your function into the template block in the window that appears.
- Click on OK.
- A define function block appears in the code window. You can now attach code blocks to it to define your function.
Checking variable types
In Scratch, two types of variables can be created (for this sprite only and for all sprites). If you’re not sure what type of variable you have created, you can check this as follows:
click on the variables section in the blocks menu and tick the box next to the relevant variable to make it visible on the stage.
If it has been created as for this sprite only it will be labelled on the stage with the name of the sprite and the variable name. For instance, the health variable created for the person sprite only will be labelled as person: health on the stage.
If it has been created as for all sprites, only the variable name will be present in the label. In the above example, the variable label will be health on the stage.
First impression - Excellent Resource
I just skim read it and it looks really good. The attention to detail, and the colour coding is very impressive. What I would really like is the scratch project to play with. I am a ‘learn through play’ kind of person and don’t really enjoy step by step instructions. However, I know there are people who LOVE to learn through step-by-step before they play. The art work and presentation is awesome.
My 9 year old son really enjoyed this
I gave this to my 9 year old. He does a code club after school so already knew scratch. On his own, he did the whole thing from start to finish in about an hour and a half (without the additional challenges) and didn’t get bored.
Was fascinating to see the graph change as the stay at home percentage was changed. He really enjoyed it.
Next thing is to play around with it – such as adding a death rate.