-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclasses.py
254 lines (225 loc) · 11.5 KB
/
classes.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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
import random
from logger import Log, Record
#==================================================================
class DayTracker:
current_day = 1
@classmethod
def increment_day(cls):
cls.current_day += 1
@classmethod
def get_current_day(cls):
return cls.current_day
@classmethod
def reset(cls):
cls.current_day = 1
#------------------------------------------------------------------
#------------------------------------------------------------------
class Being:
last_id = 0
def __init__(self, x, y, resources, is_zombie=False, esc_xp=0, win_xp=0, love_xp=0, war_xp=0, lifespan_z=10, lifespan_h=0):
Being.last_id += 1
self.id = Being.last_id
self.x = x
self.y = y
self.lifespan_h = lifespan_h
self.resources = resources # relevant only for humans
self.is_zombie = is_zombie
self.esc_xp = esc_xp
self.win_xp = win_xp
self.love_xp = love_xp
self.war_xp = war_xp
self.lifespan_z = lifespan_z # Relevant only for zombies
self.is_active = True
self.zh_kd = 0 #zombie kills as human
self.hh_kd = 0 #human kills as human
self.hz_kd = 0 #human kills as zombie
self.theft = 0
self.z_enc = 0
self.h_enc = 0
self.path = []
def move(self, dx, dy, grid):
# Ensure the being stays within the grid
self.x = max(0, min(self.x + dx, grid.width - 1))
self.y = max(0, min(self.y + dy, grid.height - 1))
log_instance = Log()
# Example of logging a movement event
log_instance.add_record(Record(day=DayTracker.get_current_day(), being_id=f"{self.id}", event_type="Movement",
description=f"ID {self.id} moved to ({dx}, {dy})"))
def encounter(self, other):
if self.is_zombie:
self.encounter_as_zombie(other)
else:
if other.is_zombie:
self.encounter_zombie(other)
else:
self.encounter_human(other)
def encounter_as_zombie(self, other):
if not other.is_zombie: # If the other being is not a zombie
# The chance of getting infected is based on the human's ability to escape or win
is_infected = random.choices(
[True, False], # True for infected, False for not infected
weights=[2, other.esc_xp + other.win_xp] # Weights: infection vs. escape or win
)[0] # [0] to get the first item from the list
if is_infected:
# Human gets infected and becomes a zombie
other.is_zombie = True
self.lifespan_z += 3 # The infecting zombie's lifespan increases
self.hz_kd += 1 # Increment the count of humans killed as a zombie- take a look at this for correct logic
log_instance = Log()
details = f"ID {self.id} contacted{other.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self.id}", event_type="INF",
description=f"{details}"))
def encounter_zombie(self, zombie):
# Decide the outcome: escape, win, or get infected
outcome = random.choices(['escape', 'win', 'infected'], weights=[self.esc_xp + 1, self.win_xp + 1, 2])[0]
self_id = f"{self.id}"
if outcome == 'escape':
self.esc_xp += 1 # Gain escape experience
self.z_enc += 1
log_instance = Log()
details = f"ID {self.id} contacted {zombie.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="ESC",
description=f"{details}"))
elif outcome == 'win':
self.win_xp += 1 # Gain win experience
self.resources += zombie.resources # Gain a small amount of resources
# kill the zombie
zombie.is_active = False
self.zh_kd += 1
log_instance = Log()
details = f"ID {self.id} contacted {zombie.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="WIN",
description=f"{details}"))
else: # infected
self.is_zombie = True
self.lifespan_z = 10 # Reset lifespan as a zombie
log_instance = Log()
details = f"ID {self.id} contacted {zombie.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="INF",
description=f"{details}"))
self.z_enc += 1
def encounter_human(self, other_human):
# Decide the outcome: love or war, ensuring weights are never zero by adding a small value
outcome = random.choices(['love', 'war'], weights=[self.love_xp + 0.1, self.war_xp + 0.1])[0]
self_id = f"{self.id}"
other_human_id = f"{other_human.id}"
if outcome == 'love':
self.love_xp += 1 # Gain love experience
other_human.love_xp += 1
avg_resources = (self.resources + other_human.resources) / 2
self.resources = other_human.resources = avg_resources # Even out resources
self.h_enc += 1
log_instance = Log()
details = f"ID {self.id} contacted {other_human.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="LUV",
description=f"{details}"))
else:
if self.war_xp > other_human.war_xp:
self.war_xp += 1 # Gain war experience
self.resources += other_human.resources # Take all resources from the defeated
other_human.resources = 0 # The defeated loses all resources
other_human.is_zombie = True # The defeated becomes a zombie
self.hh_kd += 1
self.h_enc += 1
log_instance = Log()
details = f"ID {self.id} contacted {other_human.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="WAR",
description=f"{details}"))
else:
if self.war_xp == other_human.war_xp:
theft_outcome = random.choices(['theft','war'], weights=[self.theft + 0.1, self.war_xp + 0.1])[0]
if theft_outcome == 'theft':
self.theft += 1
amount = random.randint(0,round(other_human.resources))
self.resources += amount
other_human.resources -= amount
log_instance = Log()
details = f"ID {self.id} contacted {other_human.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="STL",
description=f"{details}"))
if other_human.theft > 1:
other_human.theft -= 1
log_instance = Log()
details = f"{other_human.id}contacted {self.id} @ {other_human.x, other_human.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{other_human_id}", event_type="INF",
description=f"{details}"))
else:
other_human.theft = 0
else:
self.war_xp += 1 # Gain war experience
self.resources += other_human.resources # Take all resources from the defeated
other_human.resources = 0 # The defeated loses all resources
other_human.is_zombie = True # The defeated becomes a zombie
self.hh_kd += 1
self.h_enc += 1
log_instance = Log()
details = f"ID {self.id} contacted {other_human.id} @ {self.x, self.y}"
log_instance.add_record(
Record(day=DayTracker.get_current_day(), being_id=f"{self_id}", event_type="WAR",
description=f"{details}"))
def update_status(self):
if self.is_zombie:
self.lifespan_z -= 1 # Simulate the decay of the zombie
if self.lifespan_z <= 0:
self.is_active = False
# print(f"Being {self.id} (zombie) decayed.")
else:
if self.resources > 0:
self.resources -= 0.5 # Simulate resource consumption for humans
self.lifespan_h += 1
else:
self.is_zombie = True
self.resources= 0 # Human becomes a zombie
# print(f"Being {self.id} (human) starved.")
#-----------------------------------------------------------------
class Grid:
def __init__(self, width, height):
self.width = width
self.height = height
self.beings = []
self.rmv_beings = 0
self.occupied_positions = set()
def add_being(self, being):
while (being.x, being.y) in self.occupied_positions: # Check if position is occupied
# Generate new positions until an unoccupied one is found
being.x = random.randint(0, self.width - 1)
being.y = random.randint(0, self.height - 1)
self.occupied_positions.add((being.x, being.y)) # Mark the new position as occupied
self.beings.append(being)
def move_being(self, being):
dx = random.choice([-1, 0, 1]) # Randomly choose a direction
dy = random.choice([-1, 0, 1])
new_x = max(0, min(being.x + dx, self.width - 1))
new_y = max(0, min(being.y + dy, self.height - 1))
# Check if the new position is occupied
if (new_x, new_y) not in self.occupied_positions:
self.occupied_positions.remove((being.x, being.y))
self.occupied_positions.add((new_x, new_y))
being.move(dx, dy, grid=self)
def simulate_day(self):
for being in list(self.beings): # list copy to avoid issues while modifying the list
if being.is_active:
self.move_being(being)
for other in list(self.beings):
if being.is_active and other.is_active and being != other:
if abs(being.x - other.x) <= 1 and abs(being.y - other.y) <= 1:
being.encounter(other)
being.update_status()
# Now remove inactive beings
self.remove_inactive_beings()
def remove_inactive_beings(self):
self.beings = [being for being in self.beings if being.is_active]
# add to the number of beings removed the number self.beings list gains
self.occupied_positions = {(being.x, being.y) for being in self.beings}
def count_humans_and_zombies(self):
humans = sum(1 for being in self.beings if not being.is_zombie and being.is_active)
zombies = sum(1 for being in self.beings if being.is_zombie and being.is_active)
return humans, zombies