refactoring genes
[experiments.git] / evolution / entities.py
1
2 import copy
3 import random
4
5 from utils import SceneLogger, Vector
6
7 class Scene:
8 class Types:
9 DRAWABLE = "Drawable"
10 PHYSICAL = "Physical"
11 ALIVE = "Alive"
12 GOODS = "Goods"
13
14 class GoodTypes:
15 FOOD = "Food"
16
17 def __init__(self, name, clock):
18 self.name = name
19 self.clock = clock
20 self.all = set()
21 self.byType = {}
22 self.byEntity = {}
23 self.logger = SceneLogger(self)
24
25 def add(self, entity):
26 self.logger.debug("Scene: add %s", entity)
27 self.all.add(entity)
28 for type in entity.TYPES:
29 self.byType.setdefault(type, []).append(entity)
30
31 def remove(self, entity):
32 self.logger.debug("Scene: remove %s", entity)
33 self.all.remove(entity)
34 for type in entity.TYPES:
35 entities = self.byType.get(type, [])
36 if entity in entities: entities.remove(entity)
37
38 def getByType(self, type):
39 return self.byType.get(type, [])
40
41 def getAt(self, entity, type):
42 return [e for e in self.getByType(type) if (e.pos[0] == entity.pos[0] and e.pos[1] == entity.pos[1])]
43
44 def getAround(self, entity, distance, type):
45 def isAround(e):
46 return (e.pos - entity.pos).magnitude() < distance
47 return [e for e in self.getByType(type) if isAround(e)]
48
49
50 _entityCounter = 0
51
52 class Entity(object):
53 TYPES = []
54 def __init__(self):
55 global _entityCounter
56 self.id = _entityCounter
57 _entityCounter += 1
58
59 def __repr__(self):
60 return "%s(%d)" % (self.__class__.__name__, self.id)
61
62
63 class Physical(Entity):
64 TYPES = Entity.TYPES + [Scene.Types.DRAWABLE, Scene.Types.PHYSICAL]
65 def __init__(self, pos, walkable=True):
66 super(Physical, self).__init__()
67 self.scene = None
68 self.pos = pos
69 self.walkable = walkable
70
71 def addToScene(self, scene):
72 self.scene = scene
73 self.scene.add(self)
74 return self
75
76 def removeFromScene(self):
77 self.scene.remove(self)
78 self.scene = None
79 return self
80
81 def move(self, dv):
82 self.pos += dv
83 return self
84
85 def at(self, newPos):
86 self.pos = newPos
87 return self
88
89
90 class Good(Physical):
91 TYPES = Physical.TYPES + [Scene.Types.GOODS]
92 def __init__(self, pos):
93 super(Good, self).__init__(pos, False)
94 self.type = Scene.GoodTypes.FOOD
95 self.value = 5
96
97 def getRenderColor(self):
98 return "blue"
99
100 def use(self, e):
101 e.stats["life"] += self.value
102 self.removeFromScene()
103
104
105 class Bot(Physical):
106 TYPES = Physical.TYPES + [Scene.Types.ALIVE]
107 def __init__(self, pos):
108 super(Bot, self).__init__(pos, True)
109 self.direction = Vector(0, 0)
110 self.genes = []
111 self.stats = {"life": 10, "speed": 1}
112 self.stamina = 10
113 self.behavior = None
114 self.behaviorData = {}
115
116 def check(self):
117 badValues = [k for k, v in self.stats.iteritems() if v < 0]
118 if badValues:
119 logging.debug("%s died by bad genes: %s", self, badValues)
120
121 def addGene(self, gene):
122 self.genes.append(gene)
123 gene.apply(self)
124 self.check()
125 return self
126
127 def getGenes(self):
128 return self.genes
129
130 def getRenderColor(self):
131 return "red"
132
133
134 class Gene(object):
135 def __init__(self):
136 self.name = self.__class__.__name__
137
138 def modifyStat(self, entity, attribute, value):
139 stat = entity.stats.setdefault(attribute, 0)
140 entity.stats["stat"] = stat + value
141
142 def apply(self, entity):
143 return self
144
145 def __repr__(self):
146 return "%s" % (self.name)
147
148
149 class LongLegs(Gene):
150 def apply(self, entity):
151 self.modifyStat(entity, "speed", 0.5)
152
153 class ShortLegs(Gene):
154 def apply(self, entity):
155 self.modifyStat(entity, "speed", 0.5)
156
157 class ClassicBeauty(Gene):
158 def apply(self, entity):
159 self.modifyStat(entity, "charisma", 0.5)
160
161 class ExoticBeauty(Gene):
162 def apply(self, entity):
163 self.modifyStat(entity, "charisma", 1)
164
165 class Eyes(Gene):
166 def apply(self, entity):
167 self.modifyStat(entity, "perception", 2)
168
169
170 import inspect, sys
171 GENES = dict(inspect.getmembers(sys.modules[__name__], lambda member: inspect.isclass(member) and member.__module__ == __name__ and issubclass(member, Gene)))
172 del GENES["Gene"]
173 GENE_NAMES = GENES.keys()
174 GENE_NAMES.sort()
175 print "Available genes: ", GENE_NAMES
176