-
Notifications
You must be signed in to change notification settings - Fork 0
/
pygame_frontend.py
239 lines (203 loc) · 7.84 KB
/
pygame_frontend.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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
from typing import List
import pygame
import typing
import numpy as np
from easygui import multenterbox
import matplotlib.pyplot as plt
from ex1 import wrap_all_around_policy, all_around_policy, LocationShape, DistributionRule
from ex1 import L, P, PERSONS_DISTRIBUTION, MATRIX_SIZE, DoubtLevel, EnvMap
NUMBER_OF_PARAMETERS = 7
DEFAULT_NUMBER_OF_EPISODES = 150
Graph = typing.NamedTuple("Graph", [("graph", typing.List[int]), ("description", str), ("color", str)])
class Board:
def __init__(self, board_size, tile_size, env_map: EnvMap):
self.board_size = board_size
self.tile_size = tile_size
self.env_map = env_map
# Define the colors
self.BLACK = (0, 0, 0)
self.WHITE = (255, 255, 255)
self.GRAY = (128, 128, 128)
self.RED = (255, 0, 0)
# Create the board
self.board = [[None] * self.env_map._n_rows for _ in range(self.env_map._n_cols)]
# Initialize Pygame
pygame.init()
self.clock = pygame.time.Clock()
# Set the screen dimensions
screen_width = self.board_size * self.tile_size
screen_height = self.board_size * self.tile_size
self.screen = pygame.display.set_mode((screen_width, screen_height))
# Set the window caption
pygame.display.set_caption("Board")
def update_board(self):
for i in range(self.env_map._n_rows):
for j in range(self.env_map._n_cols):
if self.env_map._matrix[i][j].did_hear_rumour_sometime():
self.board[i][j] = self.BLACK
else:
self.board[i][j] = self.WHITE
return board
@staticmethod
def handle_quit_and_escape_events():
status = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
status = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
status = False
return status
def run(self, number_of_episodes: int = 100):
# Set the flag to continue the game
running = True
surface = pygame.display.set_mode((
self.board_size * self.tile_size + 40,
self.board_size * self.tile_size + 40 + 100 # Add 100 to account for the text box and start button
))
# Draw background
background_image = pygame.image.load('background.jpg')
surface.blit(background_image, (0, 0))
believers_percentage = []
running = True
# Loop until the user quits
for i in range(number_of_episodes):
if not running:
break
# Draw the board
print(f"turn {i}==================")
self.env_map.spread_rumor()
self.update_board()
# Draw the board
for i in range(self.board_size):
for j in range(0, self.board_size):
tile_rect = pygame.Rect(j * self.tile_size, i * self.tile_size, self.tile_size, self.tile_size)
pygame.draw.rect(surface, self.board[i][j], tile_rect, 0)
pygame.draw.rect(surface, self.GRAY, tile_rect, 1)
running = self.handle_quit_and_escape_events()
# Update the display
pygame.display.update()
self.clock.tick(100)
believers_percentage.append(env_map.calculate_percentage_of_believers())
self.clock.tick(100)
# Quit Pygame
pygame.quit()
return believers_percentage
def input_check(parameters: List[str]):
def _is_probability(p: float):
return 0 <= p <= 1
is_ok = True
if len(parameters) != NUMBER_OF_PARAMETERS:
is_ok = False
else:
n_episodes, p, d_s1, d_s2, d_s3, d_s4, n_cooldown = parameters
if sum([float(d_s1), float(d_s2), float(d_s3), float(d_s4)]) != 1:
is_ok = False
if not _is_probability(float(p)):
is_ok = False
if not n_cooldown.isnumeric() or not n_episodes.isnumeric():
is_ok = False
return is_ok
def create_insert_parameters_window():
# getting the user input for the simulation
# window title
title = "Rumour Spread simulation parameters"
# informing the user which are the default params
text = ("Those are the default parameters to the rumour spread simulation. \n"
"You are more than welcome to change them!")
# inputs fields
inputs = ["Number of episodes to run",
"P - Population density - percentage of people in the grid (0-1)",
"Percentage of S1 people - people who believe to every rumour",
"Percentage of S2 people - people who believe 2/3 of the times to rumour",
"Percentage of S3 people - people who believe 1/3 of the times to rumour",
"Percentage of S4 people - people who don't believe to rumours",
"L - number of cooldown turns"
]
# list of default params
default_params = [
DEFAULT_NUMBER_OF_EPISODES,
P,
PERSONS_DISTRIBUTION[DoubtLevel.S1],
PERSONS_DISTRIBUTION[DoubtLevel.S2],
PERSONS_DISTRIBUTION[DoubtLevel.S3],
PERSONS_DISTRIBUTION[DoubtLevel.S4],
L,
]
output = multenterbox(text, title, inputs, default_params)
if not input_check(output):
print("Wrong input, Default params are being used..")
parameters = default_params
else:
parameters = output
print(f"using parameters:{parameters}")
return parameters
def extract_parameters(parameters: List[str]):
n_episodes, p, d_s1, d_s2, d_s3, d_s4, n_cooldown = parameters
return int(n_episodes), float(p), float(d_s1), float(d_s2), float(d_s3), float(d_s4), int(n_cooldown)
def plot_experiment(graphs: typing.List[Graph], times=None, shape=None, dist=None, p=P):
for graph in graphs:
size = len(graph.graph)
plt.plot(np.arange(0, size), graph.graph, label=graph.description, color=graph.color, marker=".", markersize=5)
plt.legend()
plt.title(f"repeated experiment :={times} P:={p} shape:={shape} dist={dist}", fontsize=10)
plt.suptitle("Rumors statistics graph", fontsize=20)
plt.show()
def calc_growth(population):
growth = []
for pop in range(1, len(population)):
numbers = (population[pop] - population[pop - 1]) / population[pop - 1] * 100
growth.append(numbers)
return growth
if __name__ == "__main__":
parameters = create_insert_parameters_window()
n_episodes, p, d_s1, d_s2, d_s3, d_s4, n_cooldown = extract_parameters(parameters)
peoples_distribution = {
DoubtLevel.S1: d_s1,
DoubtLevel.S2: d_s2,
DoubtLevel.S3: d_s3,
DoubtLevel.S4: d_s4,
}
print(d_s1,d_s2,d_s3,d_s4)
TILE_SIZE = 5
env_map = EnvMap(
n_rows=MATRIX_SIZE,
n_cols=MATRIX_SIZE,
population_density=p,
persons_distribution=peoples_distribution,
cool_down_l=n_cooldown,
policy=wrap_all_around_policy,
location_shape=LocationShape.Random,
distribution_rule=DistributionRule.Random
)
# Create a new Board instance with a board size of MATRIX_SIZE and a tile size of 50
board = Board(MATRIX_SIZE, TILE_SIZE, env_map)
# Run the board program
believers_percentage = board.run(n_episodes)
plot_experiment(
[
Graph(
graph=believers_percentage,
color="blue",
description="believers percentage"
)
],
times=1,
p=p,
shape="random",
dist="random"
)
growth = calc_growth(believers_percentage)
plot_experiment(
[
Graph(
graph=growth,
color="red",
description="Believers percentage growth"
)
],
times=1,
p=p,
shape="random",
dist="random"
)