/
asn2.py
218 lines (167 loc) · 6.3 KB
/
asn2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
## CS 2120 Assignment #2 -- Zombie Apocalypse
## Name: Shi (Susan) Hu
## Student number: 250687453
import numpy
import pylab as P
#### This stuff you just have to use, you're not expected to know how it works.
#### You just need to read the plain English function headers.
#### If you want to learn more, by all means follow along (and ask questions if
#### you're curious). But you certainly don't have to.
def make_city(name,neighbours):
"""
Create a city (implemented as a list).
:param name: String containing the city name
:param neighbours: The city's row from an adjacency matrix.
:return: [name, Infection status, List of neighbours]
"""
return [name, False, list(numpy.where(neighbours==1)[0])]
def make_connections(n,density=0.25):
"""
This function will return a random adjacency matrix of size
n x n. You read the matrix like this:
if matrix[2,7] = 1, then cities '2' and '7' are connected.
if matrix[2,7] = 0, then the cities are _not_ connected.
:param n: number of cities
:param density: controls the ratio of 1s to 0s in the matrix
:returns: an n x n adjacency matrix
"""
import networkx
# Generate a random adjacency matrix and use it to build a networkx graph
a=numpy.int32(numpy.triu((numpy.random.random_sample(size=(n,n))<density)))
G=networkx.from_numpy_matrix(a)
# If the network is 'not connected' (i.e., there are isolated nodes)
# generate a new one. Keep doing this until we get a connected one.
# Yes, there are more elegant ways to do this, but I'm demonstrating
# while loops!
while not networkx.is_connected(G):
a=numpy.int32(numpy.triu((numpy.random.random_sample(size=(n,n))<density)))
G=networkx.from_numpy_matrix(a)
# Cities should be connected to themselves.
numpy.fill_diagonal(a,1)
return a + numpy.triu(a,1).T
def set_up_cities(names=['City 0', 'City 1', 'City 2', 'City 3', 'City 4', 'City 5', 'City 6', 'City 7', 'City 8', 'City 9', 'City 10', 'City 11', 'City 12', 'City 13', 'City 14', 'City 15']):
"""
Set up a collection of cities (world) for our simulator.
Each city is a 3 element list, and our world will be a list of cities.
:param names: A list with the names of the cities in the world.
:return: a list of cities
"""
# Make an adjacency matrix describing how all the cities are connected.
con = make_connections(len(names))
# Add each city to the list
city_list = []
for n in enumerate(names):
city_list += [ make_city(n[1],con[n[0]]) ]
return city_list
def draw_world(world):
"""
Given a list of cities, produces a nice graph visualization. Infected
cities are drawn as red nodes, clean cities as blue. Edges are drawn
between neighbouring cities.
:param world: a list of cities
"""
import networkx
import matplotlib.pyplot as plt
G = networkx.Graph()
bluelist=[]
redlist=[]
plt.clf()
# For each city, add a node to the graph and figure out if
# the node should be red (infected) or blue (not infected)
for city in enumerate(world):
if city[1][1] == False:
G.add_node(city[0])
bluelist.append(city[0])
else:
G.add_node(city[0],node_color='r')
redlist.append(city[0])
for neighbour in city[1][2]:
G.add_edge(city[0],neighbour)
# Lay out the nodes of the graph
position = networkx.circular_layout(G)
# Draw the nodes
networkx.draw_networkx_nodes(G,position,nodelist=bluelist, node_color="b")
networkx.draw_networkx_nodes(G,position,nodelist=redlist, node_color="r")
# Draw the edges and labels
networkx.draw_networkx_edges(G,position)
networkx.draw_networkx_labels(G,position)
# Force Python to display the updated graph
plt.show()
plt.draw()
def print_world(world):
"""
In case the graphics don't work for you, this function will print
out the current state of the world as text.
:param world: a list of cities
"""
import string
print string.ljust('City',15), 'Zombies?'
print '------------------------'
for city in world:
print string.ljust(city[0],15), city[1]
#### That's the end of the stuff provided for you.
#### Put *your* code after this comment.
#Zombify the chosen city in the list of cities
def zombify(cities,cityno):
#Set the infected property to True
cities[cityno][1] = True
#Cure the chosen city in the list of cities
def cure(cities,cityno):
#Make sure that the zeroth city is not cured
if (cityno != 0):
#Set the infected property to True
cities[cityno][1] = False
#Do one simulation of the zombie plague based on the values of p_spread and p_cure
def sim_step(cities,p_spread,p_cure):
#counter to keep track of the index of the city
counter = 0;
#Iterate through every city in the list of cities
for city in cities:
#If the city is infected , infect one of its neighbour
if city[1] and numpy.random.rand() < p_spread:
no_of_neighbours = len(city[2])
#Generate random index based on the length of the neighbour
random_city = city[2][numpy.random.randint(0, no_of_neighbours)]
#Zombify the random city
zombify(cities,random_city)
#If the city is infected , attemp to cure it
if city[1] and numpy.random.rand() < p_cure:
#Cure the current city
cure(cities,counter)
counter += 1
#Function to check whether it is the end of the world
def is_end_of_world(cities):
#Iterate through every city in the list of cities
for city in cities:
if not(city[1]):
#Return False if the city is not infected
return False
#Return true if the loop didnt find any cured cities
return True
#Function that counts how many steps it takes to reach the end of the world
def time_to_end_of_world(p_spread,p_cure):
#Sets up city
world = set_up_cities()
#Infect world 0 since it is always infected
zombify(world,0)
#Counter to keep track of the number of days it takes
day_counter = 0
#Simulate another step and count the days while its not the end of the world
while not(is_end_of_world(world)):
sim_step(world, p_spread, p_cure)
day_counter += 1
return day_counter
#Execute time_to_end_of_world n times
def end_world_many_times(n,p_spread,p_cure):
times_to_the_end_of_the_world = []
for x in range(0, n):
#Appends the number of days to a list to be returned
times_to_the_end_of_the_world.append(time_to_end_of_world(p_spread,p_cure))
print x
return times_to_the_end_of_the_world
#Graphing code
ttl = end_world_many_times(500, 1, 0)
P.hist(ttl)
P.ylabel("Number Per Bin")
P.xlabel("Number of Days")
P.show()