Last active
March 19, 2020 10:17
-
-
Save horstjens/658ba6220999e3aa27c0d67f801c2018 to your computer and use it in GitHub Desktop.
Blog Artikel spielend-programmieren
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
# TODO: include Sandwich's graphic https://imgur.com/SCrUgqq ? | |
class Person: | |
"""a person has a location, can change this location, and can be healthy, | |
infected or immune. If location is shared with an infected person, all | |
healthy persons at this location become infected. | |
After some time of infection, persons become immune and can neither | |
become infected again nor spread the infection""" | |
number = 0 | |
def __init__(self, x, y, infected=False, immune=False, stay_home = True): | |
self.number = Person.number | |
Person.number += 1 | |
Game.population[self.number] = self | |
self.x = x | |
self.y = y | |
self.infected = infected | |
self.days_infected = 0 | |
self.immune = immune | |
self.stay_home = stay_home | |
print("new person infected:", self.infected) | |
def turn(self): | |
"""a day passes, if infected long enough, person becomes immune""" | |
if self.infected: | |
self.days_infected += 1 | |
if self.days_infected > Game.infection_time: | |
self.immune = True | |
self.infected = False | |
def move_around(self): | |
if self.stay_home: | |
self.x += random.randint(-Game.low_mobile, Game.low_mobile) | |
self.y += random.randint(-Game.low_mobile, Game.low_mobile) | |
else: | |
self.x += random.randint(-Game.high_mobile, Game.high_mobile) | |
self.y += random.randint(-Game.high_mobile, Game.high_mobile) | |
self.wrap_around_edges() | |
def wrap_around_edges(self): | |
if self.x < 0: | |
self.x = Game.area[0] + self.x | |
if self.x > Game.area[0] - 1: | |
self.x = self.x - Game.area[0] | |
if self.y < 0: | |
self.y = Game.area[1] + self.y | |
if self.y > Game.area[1] - 1: | |
self.y = self.y - Game.area[1] | |
class Game: | |
# this class attributes can be overwritten by __init__ ! | |
low_mobile = 1 | |
high_mobile = 5 | |
infection_time = 20 # turns until an infected person becomes immune | |
area = (80,30) | |
percent_low_mobile = 0.8 # 80% | |
population = {} | |
history = [] | |
def __init__(self, people=10, x=80, y=30, percent_home=0.1, low_mobile = 1, high_mobile=5, infection_time = 20 ): | |
Game.area = (x,y) | |
Game.percent_low_mobile = percent_home | |
Game.low_mobile = low_mobile | |
Game.high_mobile = high_mobile | |
Game.infection_time = infection_time | |
self.percent_immune = 0.0 | |
self.percent_infected = 0.0 | |
self.percent_healthy = 1.0 | |
Game.history = [] | |
# create one infected person and other non-infected persons | |
for number in range(people): | |
# decide if this persons stays at home or no | |
home = True if random.random() < Game.percent_low_mobile else False | |
Person(x=random.randint(0,Game.area[0]-1), | |
y=random.randint(0,Game.area[1]-1), | |
infected = True if number == 0 else False, | |
immune=False, stay_home = home) | |
def turn(self): | |
"""moves all persons around""" | |
population = Game.population.values() | |
for person in population: | |
person.turn() # chance to become immune | |
person.move_around() | |
for spreader in [p for p in population if p.infected and not p.immune]: | |
for infectable in [p for p in population if not p.infected and not p.immune and p.x == spreader.x and p.y == spreader.y]: | |
infectable.infected = True # spread the infection | |
def statistic(self): | |
immune = 0 | |
infected = 0 | |
for p in Game.population.values(): | |
if p.immune: | |
immune += 1 | |
if p.infected: | |
infected += 1 | |
total = len(Game.population) | |
healthy = total - infected - immune | |
self.percent_immune = immune / total | |
self.percent_infected = infected / total | |
self.percent_healthy = 1- self.percent_infected-self.percent_immune | |
Game.history.append((healthy, infected, immune)) | |
return "healthy: {}({:.2f}%) sick: {}({:.2f}%) immune:{}({:.2f}%)".format( | |
healthy, self.percent_healthy, infected, self.percent_infected, immune, | |
self.percent_immune) | |
def draw_map(): | |
for y in range(Game.area[1]): | |
for x in range(Game.area[0]): | |
# how many people are here | |
here = [] | |
for p in Game.population.values(): | |
if p.x == x and p.y == y: | |
here.append(p) | |
infected_here = len([p2 for p2 in here if p2.infected]) | |
immune_here = len([p2 for p2 in here if p2.immune]) | |
healthy_here = len(here)-infected_here - immune_here | |
if len(here) == 0: # nobody here | |
char="." | |
elif len(here) == 1: # only one person here | |
char = "h" # healthy | |
if infected_here == 1: | |
char = "x" # sick | |
elif immune_here == 1: | |
char = "i" # immune | |
else: # several persons at the same place. | |
char = "H" # all healthy | |
if healthy_here > 0 and infected_here > 0: | |
char = "*" # spreading! | |
elif healthy_here == 0: | |
char = "-" # not spreading | |
elif immune_here == len(here): | |
char = "I" # all immune | |
elif infected_here == len(here): | |
char = "X" # all infected | |
print(char, end="") | |
print() # new line | |
def draw_graph(): | |
print("turn, x=sick, i=immune, h=healthy") | |
width = Game.area[0] | |
for number, line in enumerate(Game.history): | |
healthy, infected, immune = line | |
total = healthy + infected + immune | |
healthy_percent = healthy / total | |
infected_percent = infected / total | |
immune_percent = immune / total | |
print("{: >3}:".format(number), end="") # fill with spaces, minimum lenght is 3 | |
print("x"*int(round(infected_percent*width,0))+ | |
"i"*int(round(immune_percent*width,0))+ | |
"h"*int(round(healthy_percent*width,0))) | |
def main(people,x, y, home, low_mobile, high_mobile, infection_time ): | |
# this is the viewer | |
game = Game(people,x, y, home, low_mobile, high_mobile, infection_time) | |
legend = "h, H ........ one/many healthy persons" | |
legend += "\ni, I ........ one/many immune persons" | |
legend += "\nx, X ........ one/many sick persons" | |
legend += "\n* ........ infection spreading" | |
legend += "\n- ........ infection not spreading" | |
print(legend) | |
show_graph = False | |
show_legend = False | |
while True: | |
if show_graph: | |
draw_graph() | |
else: | |
draw_map() | |
if show_legend: | |
print(legend) | |
print(game.statistic()) | |
command = input("ENTER-> next turn, 'q'-> quit, 'g'-> toggle graph/area 'l'-> toggle legend>>>") | |
if command == "q": | |
break | |
if command == "g": | |
show_graph = not show_graph | |
if command == "l": | |
show_legend = not show_legend | |
game.turn() | |
if __name__ == "__main__": | |
main(people=200, x=80, y=30, home=0.1, low_mobile = 1, high_mobile=5, infection_time = 60 ) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment