-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmixins.py
118 lines (95 loc) · 3.35 KB
/
mixins.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
from mixin_base import MixinBase
from event import Event
import random
class Infectable(MixinBase):
"""
Mixin that keeps track of an actor's infection status,
and allows other actors to infect the actor.
"""
def __init__(self, sim, config, *args, **kwargs):
self.infected = False
self.infection_count = 0
self.infection_time = 0
self.immune = False
self.vaccinated = False
self.use_net = False
def infect(self):
if self.vaccinated:
return
if not self.infected:
self.infection_time = self.sim.t
self.infected = True
self.infection_count += 1
class Death(MixinBase):
"""
Mixin that keeps track of an actor's death status. Also contains
an event allowing other objects to hook the actor's death.
"""
def __init__(self, *a, **kwa):
self.age = 0
self._dead = False
self.on_death = Event('on_death')
self.on_death.hook(self.sim.handle_death)
def end_step(self):
if self._dead:
self.on_death.fire(self)
class NaturalDeath(Death):
"""
"""
def step(self):
die_chance = self.age * self.config.age_death_factor + self.config.death_base
if random.random() < die_chance:
self._dead = True
self.age += 1
class SimpleDeath(Death):
"""
Mixin that represents 'simple' death, i.e. a single chance
which is checked every timestep that determines whether an actor dies.
"""
def step(self):
if random.random() < self.config.simple_death_chance:
self._dead = True
class MalariaDeath(Death):
"""
Mixin that represents death by malaria.
"""
def __init__(self, *a, **kwa):
pass
def step(self):
if not self.infected or self.immune:
return
dur_fac = (self.sim.t - self.infection_time) / 10000
if not self.immune and random.random() < self.config.malaria_death_chance + dur_fac:
self._dead = True
class Hunger(MixinBase):
""" Mixin that keeps track of an actor's hunger. """
def __init__(self, sim, config, *args, **kwargs):
T = type(self)
self.hunger = self.config.fed_hunger
def step(self):
self.hunger += 1
class Actor:
"""
Represents an actor in a simulation.
Contains a reference to its parent simulation and its own configuration.
To update the actor in a timestep, call Actor.step (at the start of a timestep)
and Actor.end_step (at the end of a timestep).
To test whether an Actor is of a certain subclass, call Actor.is_<subclass>.
"""
def __init__(self, sim, config, *rest, **kwa):
self.args = (sim, config, *rest)
self.sim, self.global_config = sim, config
self.config = getattr(self.global_config, type(self).__name__)
def __repr__(self):
return f"{type(self).__name__}({self.args})"
def step(self):
""" Override to perform tasks at the start of a timestep. """
pass
def end_step(self):
""" Override to perform tasks at the end of a timestep. """
pass
def __init_subclass__(cls):
""" Augments the base class by adding is_<subclass> methods. """
super().__init_subclass__()
fn_name = f"is_{cls.__name__.lower()}"
setattr(Actor, fn_name, lambda self: isinstance(self, cls))