Lecture notes for Computer Science I by James Tam | Return to the course web page |
The goal is for students to learn to apply the above technical concepts in order to simulate and study a real life problem (the transmission of contagious diseases).
In order to better prepare for catastrophes (such as epidemics, natural disasters, and war) simulations are frequently created in order to model different scenarios (e.g., what would happen if a densely populated were evacuated if an outbreak of an infectious disease occurred, how would the plan differ for a sparsely populated city, what would the effect of channeling the evacuation through specific routes vs. opening up all the borders). For this assignment you are to write a program that will simulate an outbreak of a highly contagious disease.
Links with related material:
Running the program
The full version of the program can have the name of the input file and duration of the simulation specified as the program runs. If your program implements these capabilities then it will take the extra inputs in the following order.
<First input: name of the file that contains your Python program e.g., “infect.py”>
<Second input: the name of the input file e.g., “data.txt”>
<Third input: the number of time units that the simulation runs e.g., “20”>
So when your program is run with the example inputs, putting it all together you would type: “python infect.py data.txt 20”. If the program allows the user to specify the duration of the simulation but not the name of the input file then the second input to the program should be the number of time units that the simulation will run for. In your early versions of your solution to the assignment it's unlikely that the program will have the ability to choose the input file and duration so programs that fall into this category will be run as your previous programs have been executed (for the previous example you would just type "python infect.py").
Required setup for the assignment
Define a 2D list called ‘city’. This list will model the position of the objects in a city. Each list element will contain a reference an object that will fall into one of the following three types. You MUST define the following classes with the listed attributes as shown below.
- class Person with two attributes. Instances of this class represent the people in the simulation.
- appearance (how the object looks: single character depending upon the status of the person) : Regular ‘*’, Infected ‘@’, Deceased ‘.’
- status (an integer value that is used to store information about the person’s health: 0 (Healthy), 1 – 9 (Infected), 10 (Deceased)
- class Obstacle with one attribute. Instances of this class represent places in the city which cannot be occupied by a person (a person cannot be born there nor can a person move into a location containing an obstacle - movement only occurs in the advanced version of the assignment).
- appearance (how the object looks: by default it will be the capital ‘O’ character).
- class Empty with one attribute. Instances of class empty indicate empty spaces in the list (a person can move into or be born on an empty space)
- appearance (the appearance of an empty object: by default it will be the space ' ' character)
Notice that each class has an attribute called ‘appearance’. When you need to determine what type of object is stored in a list element then you can do so by checking its appearance. (You will also need the appearance field when you display the contents of the city as well). Before changing an attribute of an object (e.g., setting the status) you first need to ensure that type of object actually has that attribute in it's definition (e.g., Obstacles don't have a 'status'). Referring to a non-existent attribute for a class will result in an error.
Getting the starting positions
The information about the city (position of people, obstacles and empty spaces) will be loaded from file into the 2D list with all list elements containing a reference to an instance of one of the above objects that you defined in your program. The default data file “data.txt” will describe a list 8 rows x 9 columns in size. In the full version of your program it should be able to load information from an arbitrary sized file (max 36x36). Also the program should be able to determine if the data file is empty in which case the program should display a message with sufficient information to let the user know what happened (remember the rules of thumb about Interaction Design: lecture notes on loops) and the simulation should not run in this case. Finally the full version of the program should allow the user to specify the name of the input file (rather than hard-coding it as the fixed value “data.txt”). The name of the input file should be specified as the second command line argument. Example: “python infect.py disaster.txt” will use the file “disaster.txt” as the input file. Reminder: if the input file is empty then the simulation cannot run even if the user specifies a time unit larger than zero (see the next section regarding the duration of the simulation). If you are having trouble getting your file input working then you can use the initialization functions in the source code file "sample.py" (part of the support material provided for this assignment).
Time
Time passes in discrete time units (i.e., similar to the previous assignment it's a turn based simulation). The default run time on the simulation is 20 time units. The full version of the program will allow a command line argument to determine the number of time units that the simulation runs. The command line argument to determine the length of the simulation should be the third argument (after the name of the program and the name of the input file). A negative value will result in an error condition and the simulation will not run. The program begins by loading the starting positions from file and the simulation is ready to have one unit of time pass (assuming that the file wasn’t empty and that the simulation was instructed to run the simulation for at least one unit of time). As a unit of time passes the following will occur (note that the steps must be completed in the order list below because the results of previous steps can have an effect on later steps e.g., if at step 4 there are two uninfected people that are adjacent to an empty square and if one or both of these people become infected during the next step the birth will not occur at step 6).
1) Display the current time and end time for the simulation.
2) Display the current state of the world
3) Generate and display statistics about the current state of the infection. (see the section describing the statistics that will be generated and displayed).
4) The state of the infection is advanced. Healthy people are unaffected but infected people have their infection status increase by one. (People with an infection status from 1(newly infected) - 9 (critical) are in the ‘infected’ state and appear as ‘@’. People whose status reaches 10 time units reach the ‘deceased’ state and appear as ‘.’ Deceased people will no longer have their infection status increased over time).
5) Check for the transmission of new infections. The infection is transmitted from the infected and deceased to uninfected healthy people in an adjacent square. Newly infected people will have their status go from zero to one. If multiple infected/deceased people are exposed to a healthy person, the newly infected person will not have their status 'accelerated' - they will still fall in the newly infected status. Infected people cannot become 're-infected' and become more ill by successive exposure to the infected and the deceased.
6) Check for births. A person will be born into an empty square if there are at least two adjacent uninfected people. There are no limits to the number of children that a person can produce during this step.
7) Time advances by a unit.
8) The user is prompted to hit ‘enter’. The simulation will end if the specified number of time units has been reached or it will return to the first step if has not. (If the user types in a ‘d’ and hits enter then the debug state of the program will be toggled. When the program is in the debug state it should display debugging messages in a fashion similar to the previous assignment.
Display of the city
Similar to the example programs that employed lists, when city is displayed the program step through each element in the list (first traversing the columns and then the rows) but in this case you need to keep in mind that each element is not a single character so you can’t simply pass the list element to the print function. Because you now have a list of references to objects you must use instead pass the value stored in the ‘appearance’ attribute (which should contain a single character).
For instance if you were trying to display the contents of list element [0][0] you couldn’t do the following:
print city[0][0]
Because the element at this location will be a reference to an object (that is a person, obstacle or an empty space) it will have an attribute that stores information about the appearance of the object. Consequently it’s not the reference to the object that should be passed to the print function but the appearance attribute of the object:
print city[0][0].appearance
If the element is a reference to a person then a ‘*’, ‘@’ or ‘.’ will be displayed (depending upon the person’s current state). If the element refers to an obstacle then a capital ‘O’ will be displayed and if the element is a reference to an ‘Empty’ object then a single space will be displayed.
Synopsis: As you use your loops to display each list element you should not directly display each element with print but instead you should be displaying that element’s appearance field.
To make it easier to determine if the 'birth' and 'infection' features of your program are working correctly each list element is bound: above, below, left and right by a line. Also each column and row will be numbered. For cities whose columns exceeds 10 in size alphabetical letters should be used. (See the typescript files in the assignment directory for how your output should look). Keep in mind that if your program can read from an arbitrary sized input file, the generation of the labels along the rows and columns must be dynamic and determined by the size of the input file when the program runs. It must not display numberings for non-existent rows or columns.
Statistics to be generated and displayed
- The current number of healthy (uninfected people).
- The number of infected (but still living) people.
- The current population (number of healthy and infected people - to get credit for generating this statistic the previous two statistics must be correct).
- The current number of mortalities (those that occurred during that turn).
- Total mortalities (occurred since the simulation started - to get credit for generating this statistic the value for current mortalities has to be correct).
- Infection rate: the percentage of people who are currently infected (the current number of infected divided by the current population). Ideally this ratio should be shown as a percentage value with two decimal places of precision (e.g., 16.76% rather than 0.167666...). To get credit for this feature the values for the current infections and population must be correct).
Advanced versions of the assignment
Similar to the previous assignment you have the option of implementing a more challenging version of the assignment and getting extra credit for your work. If your program correctly implements all of the above features and fulfills the other non-functional requirements (style etc.) then you can add either of the following features in order to be awarded an "A+" grade.
- Graphical version. Instead of displaying the city in the form of text graphics your program uses the QuickDraw library to represent the city in the form of graphical objects. Because this assignment is largely non-interactive (doesn't ask the user for input it may be possible for any of you to implement this feature). Writing the graphical version will require a few minor changes. Instead of prompting the person to hit enter at the end of each time unit the program can instead set up a delay timer to pause the display for a few seconds. The number of seconds for the delay can be passed as fourth input to the program as it runs. The debug mode can be enabled by the user as the program is run and can take the form of the fifth command line input (although the ability to toggle the mode on/off won't be possible after the simulation has started running). Be very clear in your README file how your program should be run.
- Allow the people in the simulation to move, and you implement a disaster response plan. The default state in this version of the program is that people can now randomly move to an adjacent empty square. When the infection rate hits 50% OR if the user decides to implement the emergency response plan (by entering 'e' at the end of time unit) all mobile people (healthy and the infected) in the simulation will try to avoid the infected or the deceased and will not move onto a square that is adjacent to someone who is in either of these states. (If the person cannot avoid the infected then they won't move off their current square - which could still result in their getting infected). To avoid abnormal cases (e.g., collisions occurring because people try to move onto the same square or a person moving onto a square that was safe and ends up getting infected because a sick person moves closer after the first person moved) movement will not occur simultaneously. Instead people to the left will move before people to the right. People on a higher row will move before people on a lower row. (In effect it means that movement occurs in a 'wave' starting at the top left corner and working it's way towards the bottom right). Hint: If you do implement this advanced feature, as each time unit passes your program needs some way of tracking which people have moved and which have not moved - otherwise you may have the same person moving multiple times during the movement phase!
Final note: You will get credit for implementing one feature or the other but not both. For the typical student in this class either of these features will be quite challenging but you do have the potential of receiving a grade of "A" without implementing either advanced feature. It's likely that implementing the graphical version of the assignment will require that you design your program in a certain way at the very beginning - it will be harder to add that feature at the very end. You may be able to start work on feature #2 after you have completed all the requirements for an "A" level assignment (make sure you back it up!) so if you're not an experienced programmer then I'd recommend that you try the second feature rather than the first.
They can be found in the UNIX directory: /home/231/assignments/assignment 5 which include sample input files and the output of several runs of my solution in the form of text files (to help you understand the requirements of the assignment). Finally there is a source code python program called 'sample.py' which defines two functions. The first function will take an empty 2D list as a parameter and after the function, this list will be initialized with characters at the same position as the characters in the input file "data.txt". This 2D list should be passed to the second function which, based on the positions of the characters in this list will create a 2D list of objects at the appropriate position. This list of objects will then be returned to the caller of the second function. You are free to use functions as you see fit (don't forget to cite your source!). I included them to allow you to start and complete almost all the non-file related operations described in the assignment without knowing how file input and output work. These functions don't read information from a file but instead the information for the lists are created in a fashion similar to the creation of the list that you used in the previous assignment.