Przeglądaj źródła

remove engulf and life_game projects

Bastien Sevajol 6 lat temu
rodzic
commit
c3a25f18d4

+ 0 - 0
sandbox/engulf/__init__.py Wyświetl plik


+ 0 - 443
sandbox/engulf/behaviour.py Wyświetl plik

@@ -1,443 +0,0 @@
1
-# coding: utf-8
2
-import typing
3
-from random import choice
4
-
5
-from sandbox.engulf.const import COLLECTION_GRASS, COLLECTION_CELL, COLLECTION_ALIVE, COLLECTION_PREY
6
-from sandbox.engulf.exceptions import NotFoundWhereToGo
7
-from synergine2.simulation import Event
8
-from synergine2.simulation import SubjectBehaviour, SimulationMechanism, SimulationBehaviour, SubjectBehaviourSelector
9
-from synergine2.utils import ChunkManager
10
-from synergine2_xyz.xyz import DIRECTIONS, DIRECTION_SLIGHTLY, \
11
-    get_direction_from_north_degree
12
-from synergine2_xyz.mechanism import ProximitySubjectMechanism
13
-from synergine2_xyz.utils import get_around_positions_of_positions, get_position_for_direction
14
-
15
-# Import for typing hint
16
-if False:
17
-    from sandbox.engulf.subject import Grass
18
-    from sandbox.engulf.subject import PreyCell
19
-
20
-
21
-class GrassGrownUp(Event):
22
-    def __init__(self, subject_id, density, *args, **kwargs):
23
-        super().__init__(*args, **kwargs)
24
-        self.subject_id = subject_id
25
-        self.density = density
26
-
27
-    def repr_debug(self) -> str:
28
-        return '{}: subject_id:{}, density:{}'.format(
29
-            self.__class__.__name__,
30
-            self.subject_id,
31
-            self.density,
32
-        )
33
-
34
-
35
-class GrassSpawn(Event):
36
-    def __init__(self, subject_id, position, density, *args, **kwargs):
37
-        super().__init__(*args, **kwargs)
38
-        self.subject_id = subject_id
39
-        self.position = position
40
-        self.density = density
41
-
42
-    def repr_debug(self) -> str:
43
-        return '{}: subject_id:{}, position:{}, density:{}'.format(
44
-            self.__class__.__name__,
45
-            self.subject_id,
46
-            self.position,
47
-            self.density,
48
-        )
49
-
50
-
51
-class GrassSpotablePositionsMechanism(SimulationMechanism):
52
-    parallelizable = True
53
-
54
-    def run(self, process_number: int=None, process_count: int=None):
55
-        chunk_manager = ChunkManager(process_count)
56
-        positions = list(self.simulation.subjects.grass_xyz.keys())
57
-        positions_chunks = chunk_manager.make_chunks(positions)
58
-        spotables = []
59
-
60
-        for position in positions_chunks[process_number]:
61
-            arounds = get_around_positions_of_positions(position)
62
-            from_subject = self.simulation.subjects.grass_xyz[position][0]
63
-            around_data = {
64
-                'from_subject': from_subject,
65
-                'around': [],
66
-            }
67
-            for around in arounds:
68
-                if around not in self.simulation.subjects.grass_xyz and self.simulation.is_possible_position(around):
69
-                    around_data['around'].append(around)
70
-
71
-            if around_data['around']:
72
-                spotables.append(around_data)
73
-
74
-        return spotables
75
-
76
-
77
-class GrowUp(SubjectBehaviour):
78
-    frequency = 20
79
-
80
-    def run(self, data):
81
-        return True
82
-
83
-    def action(self, data) -> [Event]:
84
-        self.subject.density += 1
85
-        return [GrassGrownUp(
86
-            self.subject.id,
87
-            self.subject.density,
88
-        )]
89
-
90
-
91
-class GrassSpawnBehaviour(SimulationBehaviour):
92
-    frequency = 100
93
-    use = [GrassSpotablePositionsMechanism]
94
-
95
-    def run(self, data):
96
-        spawns = []
97
-
98
-        for around_data in data[GrassSpotablePositionsMechanism]:
99
-            from_subject = around_data['from_subject']
100
-            arounds = around_data['around']
101
-            if from_subject.density >= 40:
102
-                spawns.extend(arounds)
103
-
104
-        return spawns
105
-
106
-    @classmethod
107
-    def merge_data(cls, new_data, start_data=None):
108
-        start_data = start_data or []
109
-        start_data.extend(new_data)
110
-        return start_data
111
-
112
-    def action(self, data) -> [Event]:
113
-        from sandbox.engulf.subject import Grass  # cyclic
114
-        events = []
115
-
116
-        for position in data:
117
-            if position not in list(self.simulation.subjects.grass_xyz.keys()):
118
-                new_grass = Grass(
119
-                    config=self.config,
120
-                    simulation=self.simulation,
121
-                    position=position,
122
-                    density=20,
123
-                )
124
-                self.simulation.subjects.append(new_grass)
125
-                events.append(GrassSpawn(
126
-                    new_grass.id,
127
-                    new_grass.position,
128
-                    new_grass.density,
129
-                ))
130
-
131
-        return events
132
-
133
-
134
-class GrassEatableDirectProximityMechanism(ProximitySubjectMechanism):
135
-    distance = 1.41  # distance when on angle
136
-    feel_collections = [COLLECTION_GRASS]
137
-
138
-    def acceptable_subject(self, subject: 'Grass') -> bool:
139
-        return subject.density >= self.config.simulation.eat_grass_required_density
140
-
141
-
142
-class PreyEatableDirectProximityMechanism(ProximitySubjectMechanism):
143
-    distance = 1.41  # distance when on angle
144
-    feel_collections = [COLLECTION_CELL]
145
-
146
-    def acceptable_subject(self, subject: 'PreyCell') -> bool:
147
-        # TODO: N'attaquer que des "herbivores" ?
148
-        from sandbox.engulf.subject import PreyCell  # cyclic
149
-        return isinstance(subject, PreyCell)
150
-
151
-
152
-class MoveTo(Event):
153
-    def __init__(self, subject_id: int, position: tuple, *args, **kwargs):
154
-        super().__init__(*args, **kwargs)
155
-        self.subject_id = subject_id
156
-        self.position = position
157
-
158
-    def repr_debug(self) -> str:
159
-        return '{}: subject_id:{}, position:{}'.format(
160
-            type(self).__name__,
161
-            self.subject_id,
162
-            self.position,
163
-        )
164
-
165
-
166
-class EatEvent(Event):
167
-    def __init__(self, eaten_id: int, eater_id: int, eaten_new_density: float, *args, **kwargs):
168
-        super().__init__(*args, **kwargs)
169
-        self.eaten_id = eaten_id
170
-        self.eater_id = eater_id
171
-        self.eaten_new_density = eaten_new_density
172
-
173
-
174
-class EatenEvent(Event):
175
-    def __init__(self, eaten_id: int, *args, **kwargs):
176
-        super().__init__(*args, **kwargs)
177
-        self.eaten_id = eaten_id
178
-
179
-
180
-class AttackEvent(Event):
181
-    def __init__(self, attacker_id: int, attacked_id: int, *args, **kwargs):
182
-        super().__init__(*args, **kwargs)
183
-        self.attacker_id = attacker_id
184
-        self.attacked_id = attacked_id
185
-
186
-
187
-class SearchFood(SubjectBehaviour):
188
-    mechanism_data_class = NotImplemented
189
-
190
-    def get_required_appetite(self) -> float:
191
-        raise NotImplementedError()
192
-
193
-    def run(self, data):
194
-        if self.subject.appetite < self.get_required_appetite():
195
-            return False
196
-
197
-        if not data[self.mechanism_data_class]:
198
-            return False
199
-
200
-        direction_degrees = [d['direction'] for d in data[self.mechanism_data_class]]
201
-        return get_direction_from_north_degree(choice(direction_degrees))
202
-
203
-    def action(self, data) -> [Event]:
204
-        direction = data
205
-        position = get_position_for_direction(self.subject.position, direction)
206
-        self.subject.position = position
207
-        self.subject.previous_direction = direction
208
-
209
-        return [MoveTo(self.subject.id, position)]
210
-
211
-
212
-class SearchGrass(SearchFood):
213
-    """
214
-    Si une nourriture a une case de distance et cellule non rassasié, move dans sa direction.
215
-    """
216
-    use = [GrassEatableDirectProximityMechanism]
217
-    mechanism_data_class = use[0]
218
-
219
-    def get_required_appetite(self) -> float:
220
-        return self.config.simulation.search_food_appetite_required
221
-
222
-
223
-class SearchPrey(SearchFood):
224
-    """
225
-    Si une nourriture a une case de distance et cellule non rassasié, move dans sa direction.
226
-    """
227
-    use = [PreyEatableDirectProximityMechanism]
228
-    mechanism_data_class = use[0]
229
-
230
-    def get_required_appetite(self) -> float:
231
-        return self.config.simulation.search_and_attack_prey_apetite_required
232
-
233
-
234
-class EatGrass(SubjectBehaviour):
235
-    def run(self, data):
236
-        if self.subject.appetite < self.config.simulation.eat_grass_required_density:
237
-            return False
238
-
239
-        for grass in self.simulation.collections.get(COLLECTION_GRASS, []):
240
-            # TODO: Use simulation/xyz pre calculated indexes
241
-            if grass.position == self.subject.position:
242
-                return grass.id
243
-
244
-    def action(self, data) -> [Event]:
245
-        subject_id = data
246
-
247
-        grass = self.simulation.subjects.index[subject_id]  # TODO: cas ou grass disparu ?
248
-        grass.density -= self.config.simulation.eat_grass_density_reduction
249
-
250
-        self.subject.appetite -= self.config.simulation.eat_grass_appetite_reduction
251
-
252
-        # TODO: Comment mettre des logs (ne peuvent pas être passé aux subprocess)?
253
-
254
-        return [EatEvent(
255
-            eater_id=self.subject.id,
256
-            eaten_id=subject_id,
257
-            eaten_new_density=grass.density,
258
-        )]
259
-
260
-
261
-class EatPrey(SubjectBehaviour):
262
-    def run(self, data):
263
-        if self.subject.appetite < self.config.simulation.search_and_attack_prey_apetite_required:
264
-            return False
265
-
266
-        for prey in self.simulation.collections.get(COLLECTION_PREY, []):
267
-            # TODO: Use simulation/xyz pre calculated indexes
268
-            if prey.position == self.subject.position:
269
-                return prey.id
270
-
271
-    def action(self, data) -> [Event]:
272
-        subject_id = data
273
-
274
-        # Cell already eaten ?
275
-        if subject_id not in self.simulation.subjects.index:
276
-            return []
277
-
278
-        prey = self.simulation.subjects.index[subject_id]
279
-        self.simulation.subjects.remove(prey)
280
-        self.subject.appetite -= self.config.simulation.eat_prey_required_density
281
-
282
-        return [EatenEvent(
283
-            eaten_id=prey.id,
284
-        )]
285
-
286
-
287
-class Explore(SubjectBehaviour):
288
-    """
289
-    Produit un mouvement au hasard (ou un immobilisme)
290
-    """
291
-    use = []
292
-
293
-    def run(self, data):
294
-        # TODO: Il faut pouvoir dire tel behaviour concerne que tel collections
295
-        if COLLECTION_ALIVE not in self.subject.collections:
296
-            return False
297
-
298
-        return True
299
-
300
-    def action(self, data) -> [Event]:
301
-        try:
302
-            position, direction = self.get_random_position_and_direction()
303
-            self.subject.position = position
304
-            self.subject.previous_direction = direction
305
-            return [MoveTo(self.subject.id, position)]
306
-        except NotFoundWhereToGo:
307
-            return []
308
-
309
-    def get_random_position_and_direction(self) -> tuple:
310
-        attempts = 0
311
-
312
-        while attempts <= 5:
313
-            attempts += 1
314
-            direction = self.get_random_direction()
315
-            position = get_position_for_direction(self.subject.position, direction)
316
-
317
-            if self.simulation.is_possible_subject_position(self.subject, position):
318
-                return position, direction
319
-
320
-            # If blocked, permit any direction (not slightly)
321
-            if attempts >= 3:
322
-                self.subject.previous_direction = None
323
-
324
-        raise NotFoundWhereToGo()
325
-
326
-    def get_random_direction(self):
327
-        if not self.subject.previous_direction:
328
-            return choice(DIRECTIONS)
329
-        return choice(DIRECTION_SLIGHTLY[self.subject.previous_direction])
330
-
331
-
332
-class Hungry(SubjectBehaviour):
333
-    def run(self, data):
334
-        return True
335
-
336
-    def action(self, data) -> [Event]:
337
-        self.subject.appetite += self.config.simulation.hungry_reduction
338
-        return []
339
-
340
-    def get_random_direction(self):
341
-        if not self.subject.previous_direction:
342
-            return choice(DIRECTIONS)
343
-        return choice(DIRECTION_SLIGHTLY[self.subject.previous_direction])
344
-
345
-
346
-class Attack(SubjectBehaviour):
347
-    use = [PreyEatableDirectProximityMechanism]
348
-
349
-    def run(self, data):
350
-        if self.subject.appetite < self.config.simulation.search_and_attack_prey_apetite_required:
351
-            return False
352
-
353
-        eatable_datas = data[PreyEatableDirectProximityMechanism]
354
-        attackable_datas = []
355
-
356
-        for eatable_data in eatable_datas:
357
-            if COLLECTION_ALIVE in eatable_data['subject'].collections:
358
-                attackable_datas.append(eatable_data)
359
-
360
-        if attackable_datas:
361
-            return choice(attackable_datas)
362
-        return False
363
-
364
-    def action(self, data) -> [Event]:
365
-        attacked = self.simulation.subjects.index[data['subject'].id]
366
-
367
-        try:
368
-            # TODO il faut automatiser/Refactoriser le fait de retirer/ajouter un collection
369
-            self.simulation.collections[COLLECTION_ALIVE].remove(attacked)
370
-            attacked.collections.remove(COLLECTION_ALIVE)
371
-        except ValueError:
372
-            pass  # On considere qu'il a ete tué par une autre, TODO: en être sur ?
373
-
374
-        return [AttackEvent(attacker_id=self.subject.id, attacked_id=data['subject'].id)]
375
-
376
-
377
-class CellBehaviourSelector(SubjectBehaviourSelector):
378
-    # If behaviour in sublist, only one be kept in sublist
379
-    behaviour_hierarchy = (  # TODO: refact it
380
-        (
381
-            EatPrey,
382
-            EatGrass,  # TODO: Introduce priority with appetite
383
-            Attack,
384
-            SearchPrey,
385
-            SearchGrass,  # TODO: Introduce priority with appetite
386
-            Explore,
387
-        ),
388
-    )
389
-
390
-    def reduce_behaviours(
391
-        self,
392
-        behaviours: typing.Dict[typing.Type[SubjectBehaviour], object],
393
-    ) -> typing.Dict[typing.Type[SubjectBehaviour], object]:
394
-        reduced_behaviours = {}  # type: typing.Dict[typing.Type[SubjectBehaviour], object]
395
-
396
-        for behaviour_class, behaviour_data in behaviours.items():
397
-            if not self.behaviour_class_in_sublist(behaviour_class):
398
-                reduced_behaviours[behaviour_class] = behaviour_data
399
-            elif self.behaviour_class_is_prior(behaviour_class, behaviours):
400
-                reduced_behaviours[behaviour_class] = behaviour_data
401
-
402
-        return reduced_behaviours
403
-
404
-    def behaviour_class_in_sublist(self, behaviour_class: typing.Type[SubjectBehaviour]) -> bool:
405
-        for sublist in self.behaviour_hierarchy:
406
-            if behaviour_class in sublist:
407
-                return True
408
-        return False
409
-
410
-    def behaviour_class_is_prior(
411
-        self,
412
-        behaviour_class: typing.Type[SubjectBehaviour],
413
-        behaviours: typing.Dict[typing.Type[SubjectBehaviour], object],
414
-    ) -> bool:
415
-        for sublist in self.behaviour_hierarchy:
416
-            if behaviour_class in sublist:
417
-                behaviour_position = sublist.index(behaviour_class)
418
-                other_behaviour_top_position = self.get_other_behaviour_top_position(
419
-                    behaviour_class,
420
-                    behaviours,
421
-                    sublist,
422
-                )
423
-                if other_behaviour_top_position is not None and behaviour_position > other_behaviour_top_position:
424
-                    return False
425
-        return True
426
-
427
-    def get_other_behaviour_top_position(
428
-        self,
429
-        exclude_behaviour_class,
430
-        behaviours,
431
-        sublist,
432
-    ) -> typing.Union[None, int]:
433
-        position = None
434
-        for behaviour_class in behaviours.keys():
435
-            if behaviour_class != exclude_behaviour_class:
436
-                try:
437
-                    behaviour_position = sublist.index(behaviour_class)
438
-                    if position is None or behaviour_position < position:
439
-                        position = behaviour_position
440
-                except ValueError:
441
-                    pass
442
-
443
-        return position

+ 0 - 13
sandbox/engulf/config.yaml Wyświetl plik

@@ -1,13 +0,0 @@
1
-core:
2
-    cycle_duration: 0.5
3
-terminals:
4
-    sync: True
5
-simulation:
6
-    start_appetite: 50
7
-    hungry_reduction: 0.25
8
-    search_food_appetite_required: 30
9
-    search_and_attack_prey_apetite_required: 50
10
-    eat_grass_required_density: 25
11
-    eat_prey_required_density: 100
12
-    eat_grass_appetite_reduction: 5
13
-    eat_grass_density_reduction: 25

+ 0 - 9
sandbox/engulf/const.py Wyświetl plik

@@ -1,9 +0,0 @@
1
-# coding: utf-8
2
-
3
-
4
-COLLECTION_CELL = 'CELL'
5
-COLLECTION_PREY = 'PREY'
6
-COLLECTION_PREDATOR = 'PREDATOR'
7
-COLLECTION_ALIVE = 'ALIVE'
8
-COLLECTION_EATABLE = 'EATABLE'
9
-COLLECTION_GRASS = 'GRASS'

+ 0 - 6
sandbox/engulf/exceptions.py Wyświetl plik

@@ -1,6 +0,0 @@
1
-# coding: utf-8
2
-from synergine2_xyz.xyz import XYZException
3
-
4
-
5
-class NotFoundWhereToGo(XYZException):
6
-    pass

+ 0 - 184
sandbox/engulf/gui.py Wyświetl plik

@@ -1,184 +0,0 @@
1
-# coding: utf-8
2
-from random import randint
3
-
4
-import cocos
5
-from cocos.actions import MoveTo, Repeat, ScaleBy, Reverse, RotateTo
6
-from cocos.sprite import Sprite
7
-from sandbox.engulf.behaviour import GrassGrownUp, GrassSpawn, MoveTo as MoveToEvent, EatEvent, AttackEvent, EatenEvent
8
-from sandbox.engulf.subject import Cell, Grass, PreyCell, PredatorCell
9
-from synergine2.terminals import TerminalPackage, Terminal
10
-from synergine2_cocos2d.gui import Gui, GridLayerMixin
11
-from synergine2_cocos2d.gui import MainLayer as BaseMainLayer
12
-
13
-cell_scale = ScaleBy(1.1, duration=0.25)
14
-
15
-
16
-class CellsLayer(GridLayerMixin, BaseMainLayer):
17
-    def __init__(self, game: 'Game', *args, **kwargs):
18
-        super().__init__(*args, **kwargs)
19
-        self.game = game
20
-        self.cell_positions = {}
21
-        self.cell_ids = {}
22
-
23
-    @property
24
-    def move_duration(self):
25
-        return self.game.cycle_duration
26
-
27
-    @property
28
-    def fake_move_rotate_duration(self):
29
-        return self.move_duration / 3
30
-
31
-    def born(self, subject_id: int, grid_position, cell_type):
32
-        png = 'resources/cell.png' if cell_type is PreyCell else 'resources/cellp.png'
33
-
34
-        cell = Sprite(png)
35
-        cell.rotation = randint(0, 360)
36
-        self.grid_manager.scale_sprite(cell)
37
-        self.grid_manager.position_sprite(cell, grid_position)
38
-        self.cell_positions[grid_position] = cell
39
-        self.cell_ids[subject_id] = cell
40
-        cell.do(Repeat(cell_scale + Reverse(cell_scale)))
41
-        self.add(cell)
42
-
43
-    def move(self, subject_id: int, position: tuple):
44
-        if subject_id not in self.cell_ids:
45
-            return  # Cell eaten before
46
-
47
-        cell = self.cell_ids[subject_id]
48
-
49
-        window_position = self.grid_manager.get_window_position(position[0], position[1])
50
-        move_action = MoveTo(window_position, self.move_duration)
51
-
52
-        fake_rotate = RotateTo(randint(0, 360), self.fake_move_rotate_duration)
53
-
54
-        cell.do(move_action)
55
-        cell.do(fake_rotate)
56
-
57
-    def attack(self, attacker_id: int, attacked_id: int):
58
-        attacker = self.cell_ids[attacker_id]
59
-        attacker.do(ScaleBy(1.7, duration=0.25))
60
-
61
-    def eaten(self, eaten_id: int):
62
-        eaten = self.cell_ids[eaten_id]
63
-        self.remove(eaten)
64
-        # TODO: refact: On a pas nettoyer self.cell_positions par exemple
65
-        del self.cell_ids[eaten_id]
66
-
67
-
68
-class GrassLayer(GridLayerMixin, BaseMainLayer):
69
-    def __init__(self, game: 'Game', *args, **kwargs):
70
-        super().__init__(*args, **kwargs)
71
-        self.game = game
72
-        self.grasses = {}
73
-
74
-    def born(self, subject_id, grid_position, opacity=100):
75
-        grass = Sprite('resources/grass.png')
76
-        grass.rotation = randint(0, 360)
77
-        grass.opacity = opacity
78
-        self.grid_manager.scale_sprite(grass)
79
-        self.grid_manager.position_sprite(grass, grid_position)
80
-        self.grasses[subject_id] = grass
81
-        self.add(grass)
82
-
83
-    def set_density(self, subject_id, density):
84
-        self.grasses[subject_id].opacity = density
85
-
86
-
87
-class MainLayer(GridLayerMixin, BaseMainLayer):
88
-    def __init__(self, game: 'Game', terminal: Terminal, *args, **kwargs):
89
-        super().__init__(terminal, *args, **kwargs)
90
-        self.game = game
91
-        self.terminal = terminal
92
-
93
-        self.cells = CellsLayer(game=game, terminal=terminal)
94
-        self.add(self.cells)
95
-
96
-        self.grasses = GrassLayer(game=game, terminal=terminal)
97
-        self.add(self.grasses)
98
-
99
-
100
-class Game(Gui):
101
-    def __init__(self, *args, **kwargs):
102
-        super().__init__(*args, **kwargs)
103
-
104
-        self.main_layer = MainLayer(game=self, terminal=self.terminal)
105
-        self.main_scene = cocos.scene.Scene(self.main_layer)
106
-
107
-        # Event registering
108
-        self.terminal.register_event_handler(
109
-            GrassGrownUp,
110
-            self.on_grass_grown_up,
111
-        )
112
-        self.terminal.register_event_handler(
113
-            GrassSpawn,
114
-            self.on_grass_spawn,
115
-        )
116
-        self.terminal.register_event_handler(
117
-            MoveToEvent,
118
-            self.on_move_to,
119
-        )
120
-        self.terminal.register_event_handler(
121
-            EatEvent,
122
-            self.on_eat,
123
-        )
124
-        self.terminal.register_event_handler(
125
-            AttackEvent,
126
-            self.on_attack,
127
-        )
128
-        self.terminal.register_event_handler(
129
-            EatenEvent,
130
-            self.on_eaten,
131
-        )
132
-
133
-    def get_main_scene(self):
134
-        return self.main_scene
135
-
136
-    def before_received(self, package: TerminalPackage):
137
-        if package.subjects:  # It's thirst package
138
-            for subject in package.subjects:
139
-                if isinstance(subject, PreyCell):
140
-                    self.main_layer.cells.born(subject.id, subject.position, PreyCell)
141
-                if isinstance(subject, PredatorCell):
142
-                    self.main_layer.cells.born(subject.id, subject.position, PredatorCell)
143
-                if isinstance(subject, Grass):
144
-                    self.main_layer.grasses.born(
145
-                        subject.id,
146
-                        subject.position,
147
-                        subject.density,
148
-                    )
149
-
150
-    def on_grass_spawn(self, event: GrassSpawn):
151
-        self.main_layer.grasses.born(
152
-            event.subject_id,
153
-            event.position,
154
-            event.density,
155
-        )
156
-
157
-    def on_grass_grown_up(self, event: GrassGrownUp):
158
-        self.main_layer.grasses.set_density(
159
-            event.subject_id,
160
-            event.density,  # TODO: Recupe ces données depuis local plutôt que event ?
161
-        )
162
-
163
-    def on_move_to(self, event: MoveToEvent):
164
-        self.main_layer.cells.move(
165
-            event.subject_id,
166
-            event.position,
167
-        )
168
-
169
-    def on_eat(self, event: EatEvent):
170
-        self.main_layer.grasses.set_density(
171
-            event.eaten_id,
172
-            event.eaten_new_density,
173
-        )
174
-
175
-    def on_attack(self, event: AttackEvent):
176
-        self.main_layer.cells.attack(
177
-            event.attacker_id,
178
-            event.attacked_id,
179
-        )
180
-
181
-    def on_eaten(self, event: EatenEvent):
182
-        self.main_layer.cells.eaten(
183
-            event.eaten_id,
184
-        )

BIN
sandbox/engulf/resources/cell.png Wyświetl plik


BIN
sandbox/engulf/resources/cellp.png Wyświetl plik


BIN
sandbox/engulf/resources/grass.png Wyświetl plik


+ 0 - 192
sandbox/engulf/run.py Wyświetl plik

@@ -1,192 +0,0 @@
1
-"""
2
-
3
-Engulf is simulation containing:
4
-
5
-* Subjects who need to:
6
-  * eat
7
-    * low energy ground stuff
8
-    * other alive subjects
9
-    * other dead subjects
10
-  * sleep
11
-  * want to be not alone
12
-    * with non aggressive subjects
13
-  * want to be alone
14
-  * reproduce
15
-    * with non aggressive subjects
16
-    * and transmit tendencies because their cultures can be
17
-      * eat: - eat background stuff, + eat subjects
18
-      * alone/not alone: - be alone + not alone
19
-
20
-"""
21
-import logging
22
-import os
23
-import sys
24
-import typing
25
-
26
-synergine2_ath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../'))
27
-sys.path.append(synergine2_ath)
28
-
29
-from random import randint, seed
30
-from sandbox.engulf.behaviour import GrassGrownUp, GrassSpawn, MoveTo, EatEvent, AttackEvent, EatenEvent
31
-
32
-from synergine2.config import Config
33
-from synergine2.log import get_default_logger
34
-from sandbox.engulf.subject import Grass, PreyCell, PredatorCell
35
-from synergine2.core import Core
36
-from synergine2.cycle import CycleManager
37
-from synergine2.terminals import TerminalManager, Terminal, TerminalPackage
38
-from sandbox.engulf.simulation import EngulfSubjects, Engulf
39
-from synergine2_xyz.utils import get_around_positions_of, get_distance_between_points
40
-
41
-
42
-class GameTerminal(Terminal):
43
-    subscribed_events = [
44
-        GrassGrownUp,
45
-        GrassSpawn,
46
-        MoveTo,
47
-        EatEvent,
48
-        AttackEvent,
49
-        EatenEvent,
50
-    ]
51
-
52
-    def __init__(self, *args, **kwargs):
53
-        super().__init__(*args, **kwargs)
54
-        self.gui = None
55
-        self.asynchronous = False  # TODO: config
56
-
57
-    def receive(self, package: TerminalPackage):
58
-        self.gui.before_received(package)
59
-        super().receive(package)
60
-        self.gui.after_received(package)
61
-
62
-    def run(self):
63
-        from sandbox.engulf import gui
64
-        self.gui = gui.Game(self.config, self.logger, self)
65
-        self.gui.run()
66
-
67
-
68
-def fill_with_random_cells(
69
-    config,
70
-    subjects: EngulfSubjects,
71
-    count: int,
72
-    start_position: tuple,
73
-    end_position: tuple,
74
-    cell_class: typing.Type[PreyCell],
75
-) -> None:
76
-    cells = []
77
-
78
-    while len(cells) < count:
79
-        position = (
80
-            randint(start_position[0], end_position[0]+1),
81
-            randint(start_position[1], end_position[1]+1),
82
-            0,
83
-        )
84
-        if position not in subjects.cell_xyz:
85
-            cell = cell_class(
86
-                config,
87
-                simulation=subjects.simulation,
88
-                position=position,
89
-            )
90
-            cells.append(cell)
91
-            subjects.append(cell)
92
-
93
-
94
-def fill_with_random_grass(
95
-    config,
96
-    subjects: EngulfSubjects,
97
-    start_count: int,
98
-    start_position: tuple,
99
-    end_position: tuple,
100
-    density: int=5,
101
-) -> None:
102
-    grasses = []
103
-
104
-    while len(grasses) < start_count:
105
-        position = (
106
-            randint(start_position[0], end_position[0]+1),
107
-            randint(start_position[1], end_position[1]+1),
108
-            0,
109
-        )
110
-
111
-        if position not in subjects.grass_xyz:
112
-            grass = Grass(
113
-                config,
114
-                simulation=subjects.simulation,
115
-                position=position,
116
-            )
117
-            grasses.append(grass)
118
-            subjects.append(grass)
119
-
120
-    for grass in grasses:
121
-        for around in get_around_positions_of(grass.position, distance=density):
122
-            if around not in subjects.grass_xyz:
123
-                if subjects.simulation.is_possible_position(around):
124
-                    new_grass = Grass(
125
-                        config,
126
-                        simulation=subjects.simulation,
127
-                        position=around,
128
-                    )
129
-                    distance = get_distance_between_points(around, grass.position)
130
-                    new_grass.density = 100 - round((distance * 100) / 7)
131
-                    subjects.append(new_grass)
132
-
133
-
134
-def main():
135
-    seed(42)
136
-
137
-    config = Config()
138
-    config.load_files(['sandbox/engulf/config.yaml'])
139
-    logger = get_default_logger(level=logging.DEBUG)
140
-
141
-    simulation = Engulf(config)
142
-    subjects = EngulfSubjects(simulation=simulation)
143
-    fill_with_random_cells(
144
-        config,
145
-        subjects,
146
-        30,
147
-        (-34, -34, 0),
148
-        (34, 34, 0),
149
-        cell_class=PreyCell,
150
-    )
151
-    fill_with_random_cells(
152
-        config,
153
-        subjects,
154
-        30,
155
-        (-34, -34, 0),
156
-        (34, 34, 0),
157
-        cell_class=PredatorCell,
158
-    )
159
-    fill_with_random_grass(
160
-        config,
161
-        subjects,
162
-        5,
163
-        (-34, -34, 0),
164
-        (34, 34, 0),
165
-    )
166
-    simulation.subjects = subjects
167
-
168
-    core = Core(
169
-        config=config,
170
-        logger=logger,
171
-        simulation=simulation,
172
-        cycle_manager=CycleManager(
173
-            config=config,
174
-            logger=logger,
175
-            simulation=simulation,
176
-        ),
177
-        terminal_manager=TerminalManager(
178
-            config=config,
179
-            logger=logger,
180
-            terminals=[GameTerminal(
181
-                config,
182
-                logger,
183
-                asynchronous=False,
184
-            )]
185
-        ),
186
-        cycles_per_seconds=1/config.core.cycle_duration,
187
-    )
188
-    core.run()
189
-
190
-
191
-if __name__ == '__main__':
192
-    main()

+ 0 - 61
sandbox/engulf/simulation.py Wyświetl plik

@@ -1,61 +0,0 @@
1
-# coding: utf-8
2
-from sandbox.engulf.behaviour import GrassSpawnBehaviour
3
-from sandbox.engulf.subject import Cell, Grass
4
-from synergine2_xyz.xyz import XYZSubjectMixin
5
-from synergine2_xyz.subjects import XYZSubjects
6
-from synergine2_xyz.simulation import XYZSimulation
7
-
8
-__author__ = 'bux'
9
-
10
-
11
-class EngulfSubjects(XYZSubjects):
12
-    def __init__(self, *args, **kwargs):
13
-        super().__init__(*args, **kwargs)
14
-        # TODO: accept multiple subjects as same position
15
-        # TODO: init xyz with given list
16
-        self.cell_xyz = {}
17
-        self.grass_xyz = {}
18
-
19
-    def remove(self, value: XYZSubjectMixin):
20
-        super().remove(value)
21
-
22
-        if isinstance(value, Cell):
23
-            try:
24
-                self.cell_xyz.get(value.position, []).remove(value)
25
-                if not self.cell_xyz[value.position]:
26
-                    del self.cell_xyz[value.position]
27
-            except ValueError:
28
-                pass
29
-
30
-        if isinstance(value, Grass):
31
-            del self.grass_xyz[value.position]
32
-
33
-    def append(self, p_object: XYZSubjectMixin):
34
-        super().append(p_object)
35
-
36
-        if isinstance(p_object, Cell):
37
-            self.cell_xyz.setdefault(p_object.position, []).append(p_object)
38
-
39
-        if isinstance(p_object, Grass):
40
-            self.grass_xyz.setdefault(p_object.position, []).append(p_object)
41
-
42
-
43
-class Engulf(XYZSimulation):
44
-    behaviours_classes = [
45
-        GrassSpawnBehaviour,
46
-    ]
47
-
48
-    def is_possible_position(self, position: tuple) -> bool:
49
-        top_left = (-35, -35, 0)
50
-        bottom_right = (35, 35, 0)
51
-
52
-        pos_x = position[0]
53
-        pos_y = position[1]
54
-
55
-        if pos_x < top_left[0] or pos_x > bottom_right[0]:
56
-            return False
57
-
58
-        if pos_y < top_left[1] or pos_y > bottom_right[1]:
59
-            return False
60
-
61
-        return True

+ 0 - 75
sandbox/engulf/subject.py Wyświetl plik

@@ -1,75 +0,0 @@
1
-# coding: utf-8
2
-from sandbox.engulf.behaviour import GrowUp, SearchGrass, EatGrass, Explore, CellBehaviourSelector, Hungry, Attack, \
3
-    SearchPrey, EatPrey
4
-from sandbox.engulf.const import COLLECTION_CELL, COLLECTION_ALIVE, COLLECTION_EATABLE, COLLECTION_GRASS, \
5
-    COLLECTION_PREY, COLLECTION_PREDATOR
6
-from synergine2.simulation import Subject
7
-from synergine2_xyz.xyz import XYZSubjectMixin
8
-
9
-
10
-class Cell(XYZSubjectMixin, Subject):
11
-    collections = [
12
-        COLLECTION_CELL,
13
-        COLLECTION_ALIVE,
14
-        COLLECTION_EATABLE,
15
-    ]
16
-    # TODO: Mettre en place la "selection/choix": car il y a deux move possible chaque cycle ci-dessous.
17
-    behaviours_classes = [
18
-        Explore,
19
-        Hungry,
20
-    ]
21
-    behaviour_selector_class = CellBehaviourSelector
22
-
23
-    def __init__(self, *args, **kwargs):
24
-        super().__init__(*args, **kwargs)
25
-        self._appetite = self.config.simulation.start_appetite  # /100
26
-
27
-    @property
28
-    def appetite(self) -> float:
29
-        return self._appetite
30
-
31
-    @appetite.setter
32
-    def appetite(self, value) -> None:
33
-        if value > 100:
34
-            self._appetite = 100
35
-        elif value < 0:
36
-            self._appetite = 0
37
-        else:
38
-            self._appetite = value
39
-
40
-
41
-class PreyCell(Cell):
42
-    collections = Cell.collections[:] + [COLLECTION_PREY]
43
-    behaviours_classes = Cell.behaviours_classes[:] + [SearchGrass, EatGrass]
44
-
45
-
46
-class PredatorCell(Cell):
47
-    collections = Cell.collections[:] + [COLLECTION_PREDATOR]
48
-    behaviours_classes = Cell.behaviours_classes[:] + [SearchPrey, Attack, EatPrey]
49
-
50
-
51
-class Grass(XYZSubjectMixin, Subject):
52
-    collections = [
53
-        COLLECTION_EATABLE,
54
-        COLLECTION_GRASS,
55
-    ]
56
-    behaviours_classes = [
57
-        GrowUp,
58
-    ]
59
-
60
-    def __init__(self, *args, **kwargs):
61
-        self._density = kwargs.pop('density', 100.0)
62
-        super().__init__(*args, **kwargs)
63
-
64
-    @property
65
-    def density(self) -> float:
66
-        return self._density
67
-
68
-    @density.setter
69
-    def density(self, value: float) -> None:
70
-        if value > 100:
71
-            self._density = 100
72
-        elif value < 0:
73
-            self._density = 0
74
-        else:
75
-            self._density = value

+ 0 - 0
sandbox/life_game/__init__.py Wyświetl plik


+ 0 - 4
sandbox/life_game/config.yaml Wyświetl plik

@@ -1,4 +0,0 @@
1
-core:
2
-    cycle_duration: 0.5
3
-terminals:
4
-    sync: True

+ 0 - 152
sandbox/life_game/gui.py Wyświetl plik

@@ -1,152 +0,0 @@
1
-# coding: utf-8
2
-import cocos
3
-from cocos.actions import ScaleBy, Repeat, Reverse, RotateBy
4
-from cocos.director import director
5
-from cocos.layer import ScrollableLayer, Layer
6
-from cocos.sprite import Sprite
7
-from pyglet.window import key as wkey
8
-from random import randint
9
-from sandbox.life_game.simulation import CellBornEvent
10
-from sandbox.life_game.simulation import CellDieEvent, Cell, InvertCellStateBehaviour, \
11
-    EmptyPositionWithLotOfCellAroundEvent
12
-from synergine2.config import Config
13
-from synergine2.log import SynergineLogger
14
-from synergine2.terminals import Terminal
15
-from synergine2.terminals import TerminalPackage
16
-from synergine2_cocos2d.gui import Gui, GridLayerMixin, MainLayer as BaseMainLayer
17
-
18
-cell_scale = ScaleBy(1.1, duration=0.25)
19
-cell_rotate = RotateBy(360, duration=30)
20
-flash_flash = ScaleBy(8, duration=0.5)
21
-flash_rotate = RotateBy(360, duration=6)
22
-
23
-
24
-class Cells(GridLayerMixin, Layer):
25
-    def __init__(self):
26
-        super().__init__()
27
-        self.cells = {}
28
-        self.flashs = []
29
-
30
-    def born(self, grid_position):
31
-        if grid_position in self.cells:
32
-            return  # cell can be added by gui
33
-
34
-        cell = Sprite('resources/cells_l.png')
35
-        cell.rotation = randint(0, 360)
36
-        self.grid_manager.scale_sprite(cell)
37
-        self.grid_manager.position_sprite(cell, grid_position)
38
-        cell.do(Repeat(cell_scale + Reverse(cell_scale)))
39
-        cell.do(Repeat(cell_rotate + Reverse(cell_rotate)))
40
-        self.cells[grid_position] = cell
41
-        self.add(cell)
42
-
43
-    def die(self, grid_position):
44
-        try:
45
-            self.remove(self.cells[grid_position])
46
-            del self.cells[grid_position]
47
-        except KeyError:
48
-            pass  # Cell can be removed by gui
49
-
50
-    def flash(self, position):
51
-        flash = Sprite('resources/flash.png')
52
-        flash.opacity = 40
53
-        flash.scale = 0.1
54
-        flash.rotation = randint(0, 360)
55
-        flash.do(flash_flash + Reverse(flash_flash))
56
-        flash.do(Repeat(flash_rotate + Reverse(flash_rotate)))
57
-        self.grid_manager.position_sprite(flash, position)
58
-        self.flashs.append(flash)
59
-        self.add(flash)
60
-
61
-
62
-class MainLayer(GridLayerMixin, BaseMainLayer):
63
-    is_event_handler = True
64
-
65
-    def __init__(self, *args, **kwargs):
66
-        super().__init__(*args, **kwargs)
67
-
68
-        self.background = Sprite('resources/banner-1711735_640.jpg')
69
-        self.background.position = 0, 0
70
-        self.background.opacity = 70
71
-        self.background.scale = 5
72
-        self.add(self.background, z=1)
73
-
74
-        self.cells = Cells()
75
-        self.add(self.cells)
76
-
77
-        self.cross = Sprite('resources/cross31x31.png')
78
-        self.cross.position = 0, 0
79
-        self.cross.opacity = 50
80
-        self.add(self.cross)
81
-
82
-        # Set scene center on center of screen
83
-        window_size = director.get_window_size()
84
-        self.position = window_size[0] // 2, window_size[1] // 2
85
-
86
-    def on_mouse_press(self, x, y, buttons, modifiers):
87
-        x, y = director.get_virtual_coordinates(x, y)
88
-        grid_position = self.grid_manager.get_grid_position(x, y)
89
-
90
-        self.terminal.send(TerminalPackage(
91
-            simulation_actions=[(InvertCellStateBehaviour, {'position': grid_position})],
92
-        ))
93
-
94
-    def on_mouse_motion(self, x, y, dx, dy):
95
-        x, y = director.get_virtual_coordinates(x, y)
96
-        grid_position = self.grid_manager.get_grid_position(x, y)
97
-        window_position = self.grid_manager.get_window_position(grid_position[0], grid_position[1])
98
-
99
-        self.cross.position = window_position
100
-
101
-
102
-class LifeGameGui(Gui):
103
-    def __init__(
104
-            self,
105
-            config: Config,
106
-            logger: SynergineLogger,
107
-            terminal: Terminal,
108
-            read_queue_interval: float=1 / 60.0,
109
-    ):
110
-        super().__init__(config, logger, terminal, read_queue_interval)
111
-
112
-        self.main_layer = MainLayer(terminal=self.terminal)
113
-        self.main_scene = cocos.scene.Scene(self.main_layer)
114
-        self.positions = {}
115
-
116
-        self.terminal.register_event_handler(CellDieEvent, self.on_cell_die)
117
-        self.terminal.register_event_handler(CellBornEvent, self.on_cell_born)
118
-        self.terminal.register_event_handler(
119
-            EmptyPositionWithLotOfCellAroundEvent,
120
-            self.on_empty_cell_with_lot_of_cell_around,
121
-        )
122
-
123
-    def get_main_scene(self):
124
-        return self.main_scene
125
-
126
-    def before_received(self, package: TerminalPackage):
127
-        if package.subjects:  # It's thirst package
128
-            for subject in package.subjects:
129
-                if isinstance(subject, Cell):
130
-                    self.positions[subject.id] = subject.position
131
-                    self.main_layer.cells.born(subject.position)
132
-
133
-        for flash in self.main_layer.cells.flashs[:]:
134
-            self.main_layer.cells.flashs.remove(flash)
135
-            self.main_layer.cells.remove(flash)
136
-
137
-    def on_cell_die(self, event: CellDieEvent):
138
-        try:
139
-            self.main_layer.cells.die(self.positions[event.subject_id])
140
-        except KeyError:
141
-            pass
142
-
143
-    def on_cell_born(self, event: CellBornEvent):
144
-        if event.subject_id not in self.terminal.subjects:
145
-            return
146
-
147
-        subject = self.terminal.subjects.get(event.subject_id)
148
-        self.positions[event.subject_id] = subject.position
149
-        self.main_layer.cells.born(subject.position)
150
-
151
-    def on_empty_cell_with_lot_of_cell_around(self, event: EmptyPositionWithLotOfCellAroundEvent):
152
-        self.main_layer.cells.flash(event.position)

BIN
sandbox/life_game/resources/banner-1711735_640.jpg Wyświetl plik


BIN
sandbox/life_game/resources/cells_l.png Wyświetl plik


BIN
sandbox/life_game/resources/cross31x31.png Wyświetl plik


BIN
sandbox/life_game/resources/flash.png Wyświetl plik


+ 0 - 158
sandbox/life_game/run.py Wyświetl plik

@@ -1,158 +0,0 @@
1
-# coding: utf-8
2
-import logging
3
-import os
4
-import sys
5
-
6
-synergine2_ath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../'))
7
-sys.path.append(synergine2_ath)
8
-
9
-import collections
10
-
11
-from synergine2.config import Config
12
-from synergine2.log import get_default_logger
13
-from sandbox.life_game.simulation import Cell, LifeGame, \
14
-    EmptyPositionWithLotOfCellAroundEvent
15
-from sandbox.life_game.simulation import Empty
16
-from sandbox.life_game.simulation import CellDieEvent
17
-from sandbox.life_game.simulation import CellBornEvent
18
-from sandbox.life_game.utils import get_subjects_from_str_representation
19
-from synergine2.core import Core
20
-from synergine2.cycle import CycleManager
21
-from synergine2.simulation import Event
22
-from synergine2.terminals import Terminal
23
-from synergine2.terminals import TerminalPackage
24
-from synergine2.terminals import TerminalManager
25
-from synergine2_xyz.utils import get_str_representation_from_positions
26
-
27
-
28
-class SimplePrintTerminal(Terminal):
29
-    subscribed_events = [
30
-        CellDieEvent,
31
-        CellBornEvent,
32
-    ]
33
-
34
-    def __init__(self, *args, **kwargs):
35
-        super().__init__(*args, **kwargs)
36
-        self._cycle_born_count = 0
37
-        self._cycle_die_count = 0
38
-        self.register_event_handler(CellDieEvent, self.record_die)
39
-        self.register_event_handler(CellBornEvent, self.record_born)
40
-
41
-    def record_die(self, event: Event):
42
-        self._cycle_die_count += 1
43
-
44
-    def record_born(self, event: Event):
45
-        self._cycle_born_count += 1
46
-
47
-    def receive(self, package: TerminalPackage):
48
-        self._cycle_born_count = 0
49
-        self._cycle_die_count = 0
50
-        super().receive(package)
51
-        self.print_str_representation()
52
-
53
-    def print_str_representation(self):
54
-        items_positions = collections.defaultdict(list)
55
-        for subject in self.subjects.values():
56
-            if type(subject) == Cell:
57
-                items_positions['1'].append(subject.position)
58
-            if type(subject) == Empty:
59
-                items_positions['0'].append(subject.position)
60
-        print(get_str_representation_from_positions(
61
-            items_positions,
62
-            separator=' ',
63
-            force_items_as=(('0', ' '),),
64
-            # force_positions_as=(
65
-            #     ((-3, -10, 0), 'V'),
66
-            #     ((-2, -9, 0), 'X'),
67
-            # )
68
-        ))
69
-
70
-        # Display current cycle events
71
-        print('This cycle: {0} born, {1} dead'.format(
72
-            self._cycle_born_count,
73
-            self._cycle_die_count,
74
-        ))
75
-
76
-        print()
77
-
78
-
79
-class CocosTerminal(Terminal):
80
-    subscribed_events = [
81
-        CellDieEvent,
82
-        CellBornEvent,
83
-        EmptyPositionWithLotOfCellAroundEvent,
84
-    ]
85
-
86
-    def __init__(self, *args, **kwargs):
87
-        super().__init__(*args, **kwargs)
88
-        self.subjects = None
89
-        self.gui = None
90
-
91
-    def receive(self, package: TerminalPackage):
92
-        self.gui.before_received(package)
93
-        super().receive(package)
94
-        self.gui.after_received(package)
95
-
96
-    def run(self):
97
-        from sandbox.life_game import gui
98
-        self.gui = gui.LifeGameGui(self.config, self.logger, self)
99
-        self.gui.run()
100
-
101
-
102
-def main():
103
-    start_str_representation = """
104
-        0 0 0 0 0 0 0 0 0 0 0 0 0
105
-        0 0 0 1 1 1 1 0 0 0 0 0 0
106
-        0 0 0 1 0 0 1 0 0 0 0 0 0
107
-        0 1 1 1 0 0 1 1 1 0 0 0 0
108
-        0 1 0 0 0 0 0 0 1 0 0 0 0
109
-        0 1 0 0 0 0 0 0 1 0 0 0 0
110
-        0 1 1 1 0 0 1 1 1 0 0 0 0
111
-        0 0 0 1 0 0 1 0 0 0 0 0 0
112
-        0 0 0 1 1 1 1 0 0 0 0 0 0
113
-        0 0 0 0 0 0 0 0 0 0 0 0 0
114
-        0 0 0 0 0 0 0 0 0 0 0 0 0
115
-        0 0 0 0 0 0 0 0 0 0 0 0 0
116
-        0 0 0 0 0 0 0 0 0 0 0 0 0
117
-        0 0 0 0 0 0 0 0 0 0 0 0 0
118
-        0 0 0 0 0 1 1 1 0 0 0 0 0
119
-        0 0 0 0 0 0 0 1 0 0 0 0 0
120
-        0 0 0 0 0 0 1 0 0 0 0 0 0
121
-        0 0 0 0 0 0 0 0 0 0 0 0 0
122
-        0 0 0 0 0 0 0 0 0 0 0 0 0
123
-    """
124
-
125
-    config = Config()
126
-    config.load_files(['sandbox/life_game/config.yaml'])
127
-    logger = get_default_logger(level=logging.DEBUG)
128
-
129
-    simulation = LifeGame(config)
130
-    subjects = get_subjects_from_str_representation(
131
-        start_str_representation,
132
-        simulation,
133
-    )
134
-    simulation.subjects = subjects
135
-
136
-    core = Core(
137
-        config=config,
138
-        logger=logger,
139
-        simulation=simulation,
140
-        cycle_manager=CycleManager(
141
-            config=config,
142
-            logger=logger,
143
-            simulation=simulation,
144
-        ),
145
-        terminal_manager=TerminalManager(
146
-            config=config,
147
-            logger=logger,
148
-            terminals=[
149
-                CocosTerminal(config, logger),
150
-                SimplePrintTerminal(config, logger),
151
-            ]
152
-        ),
153
-    )
154
-    core.run()
155
-
156
-
157
-if __name__ == '__main__':
158
-    main()

+ 0 - 189
sandbox/life_game/simulation.py Wyświetl plik

@@ -1,189 +0,0 @@
1
-# coding: utf-8
2
-from synergine2.simulation import Event
3
-from synergine2.simulation import SimulationBehaviour
4
-from synergine2.simulation import Subject, SimulationMechanism
5
-from synergine2.simulation import SubjectBehaviour
6
-from synergine2.utils import ChunkManager
7
-from synergine2_xyz.xyz import ProximityMixin
8
-from synergine2_xyz.mechanism import ProximitySubjectMechanism
9
-from synergine2_xyz.simulation import XYZSimulation
10
-from synergine2_xyz.xyz import XYZSubjectMixin
11
-from synergine2_xyz.utils import get_around_positions_of_positions, get_min_and_max
12
-
13
-COLLECTION_CELL = 'COLLECTION_CELL'  # Collections of Cell type
14
-
15
-
16
-class CellDieEvent(Event):
17
-    def __init__(self, subject_id, *args, **kwargs):
18
-        super().__init__(*args, **kwargs)
19
-        self.subject_id = subject_id
20
-
21
-
22
-class CellBornEvent(Event):
23
-    def __init__(self, subject_id, *args, **kwargs):
24
-        super().__init__(*args, **kwargs)
25
-        self.subject_id = subject_id
26
-
27
-
28
-class EmptyPositionWithLotOfCellAroundEvent(Event):
29
-    def __init__(self, position, *args, **kwargs):
30
-        super().__init__(*args, **kwargs)
31
-        self.position = position
32
-
33
-
34
-class CellProximityMechanism(ProximitySubjectMechanism):
35
-    distance = 1.41  # distance when on angle
36
-    feel_collections = [COLLECTION_CELL]
37
-
38
-
39
-class CellAroundAnEmptyPositionMechanism(ProximityMixin, SimulationMechanism):
40
-    distance = 1.41  # distance when on angle
41
-    feel_collections = [COLLECTION_CELL]
42
-    parallelizable = True
43
-
44
-    def run(self, process_number: int=None, process_count: int=None):
45
-        chunk_manager = ChunkManager(process_count)
46
-        positions = self.simulation.subjects.xyz.keys()
47
-        min_x, max_x, min_y, max_y, min_z, max_z = get_min_and_max(positions)
48
-        xs = list(range(min_x, max_x+1))
49
-        xs_chunks = chunk_manager.make_chunks(xs)
50
-
51
-        results = {}
52
-        for z in range(min_z, max_z+1):
53
-            for y in range(min_y, max_y+1):
54
-                for x in xs_chunks[process_number]:
55
-                    subject_here = self.simulation.subjects.xyz.get((x, y, z))
56
-                    if not subject_here or isinstance(subject_here, Empty):
57
-                        subjects = self.get_for_position(
58
-                            position=(x, y, z),
59
-                            simulation=self.simulation,
60
-                        )
61
-                        results[(x, y, z)] = subjects
62
-
63
-        return results
64
-
65
-
66
-class CellDieBehaviour(SubjectBehaviour):
67
-    use = [CellProximityMechanism]
68
-
69
-    def run(self, data):
70
-        around_count = len(data[CellProximityMechanism])
71
-        if around_count in [2, 3]:
72
-            return False
73
-        # If we return around_count, when around_count is 0,
74
-        # cycle manager will consider as False
75
-        return True
76
-
77
-    def action(self, data):
78
-        new_empty = Empty(
79
-            config=self.config,
80
-            simulation=self.simulation,
81
-            position=self.subject.position,
82
-        )
83
-        self.simulation.subjects.remove(self.subject)
84
-        self.simulation.subjects.append(new_empty)
85
-        return [CellDieEvent(self.subject.id)]
86
-
87
-
88
-class CellBornBehaviour(SubjectBehaviour):
89
-    use = [CellProximityMechanism]
90
-
91
-    def run(self, data):
92
-        around_count = len(data[CellProximityMechanism])
93
-        if around_count == 3:
94
-            return 3
95
-        return False
96
-
97
-    def action(self, data):
98
-        new_cell = Cell(
99
-            config=self.config,
100
-            simulation=self.simulation,
101
-            position=self.subject.position,
102
-        )
103
-
104
-        positions_to_complete = get_around_positions_of_positions(self.subject.position)
105
-        for position in positions_to_complete:
106
-            if position not in self.simulation.subjects.xyz:
107
-                new_empty = Empty(
108
-                    config=self.config,
109
-                    simulation=self.simulation,
110
-                    position=position,
111
-                )
112
-                # Ici on casse le SimplePrintTerminal (car on créer des ligne avec des espaces manquants ?)
113
-                self.simulation.subjects.append(new_empty)
114
-
115
-        self.simulation.subjects.remove(self.subject)
116
-        self.simulation.subjects.append(new_cell)
117
-        return [CellBornEvent(new_cell.id)]
118
-
119
-
120
-class InvertCellStateBehaviour(SimulationBehaviour):
121
-    def run(self, data):
122
-        pass  # This behaviour is designed to be launch by terminal
123
-
124
-    def action(self, data) -> [Event]:
125
-        position = data['position']
126
-        cell_at_position = self.simulation.subjects.xyz.get(position, None)
127
-
128
-        if not cell_at_position or isinstance(cell_at_position, Empty):
129
-            new_cell = Cell(
130
-                config=self.config,
131
-                simulation=self.simulation,
132
-                position=position,
133
-            )
134
-            if cell_at_position:
135
-                self.simulation.subjects.remove(cell_at_position)
136
-            self.simulation.subjects.append(new_cell)
137
-            return [CellBornEvent(new_cell.id)]
138
-
139
-        new_empty = Empty(
140
-            config=self.config,
141
-            simulation=self.simulation,
142
-            position=position,
143
-        )
144
-
145
-        self.simulation.subjects.remove(cell_at_position)
146
-        self.simulation.subjects.append(new_empty)
147
-        return [CellDieEvent(new_empty)]
148
-
149
-
150
-class LotOfCellsSignalBehaviour(SimulationBehaviour):
151
-    use = [CellAroundAnEmptyPositionMechanism]
152
-
153
-    def run(self, data):
154
-        positions = []
155
-
156
-        for position, subjects in data[CellAroundAnEmptyPositionMechanism].items():
157
-            if len(subjects) >= 4:
158
-                positions.append(position)
159
-
160
-        return positions
161
-
162
-    @classmethod
163
-    def merge_data(cls, new_data, start_data=None):
164
-        start_data = start_data or []
165
-        start_data.extend(new_data)
166
-        return start_data
167
-
168
-    def action(self, data) -> [Event]:
169
-        events = []
170
-
171
-        for position in data:
172
-            events.append(EmptyPositionWithLotOfCellAroundEvent(position))
173
-
174
-        return events
175
-
176
-
177
-class Cell(XYZSubjectMixin, Subject):
178
-    collections = Subject.collections[:]
179
-    collections.extend([COLLECTION_CELL])
180
-    behaviours_classes = [CellDieBehaviour]
181
-
182
-
183
-class Empty(XYZSubjectMixin, Subject):
184
-    """Represent empty position where cell can spawn"""
185
-    behaviours_classes = [CellBornBehaviour]
186
-
187
-
188
-class LifeGame(XYZSimulation):
189
-    behaviours_classes = [LotOfCellsSignalBehaviour]

+ 0 - 29
sandbox/life_game/utils.py Wyświetl plik

@@ -1,29 +0,0 @@
1
-# coding: utf-8
2
-from sandbox.life_game.simulation import Cell
3
-from sandbox.life_game.simulation import Empty
4
-from synergine2.simulation import Simulation
5
-from synergine2_xyz.subjects import XYZSubjects
6
-from synergine2_xyz.utils import get_positions_from_str_representation
7
-
8
-
9
-def get_subjects_from_str_representation(
10
-    str_representations: str,
11
-    simulation: Simulation,
12
-) -> [Cell, Empty]:
13
-    subjects = XYZSubjects(simulation=simulation)
14
-    items_positions = get_positions_from_str_representation(str_representations)
15
-    for item, positions in items_positions.items():
16
-        for position in positions:
17
-            if item == '0':
18
-                subjects.append(Empty(
19
-                    config=simulation.config,
20
-                    simulation=simulation,
21
-                    position=position,
22
-                ))
23
-            if item == '1':
24
-                subjects.append(Cell(
25
-                    config=simulation.config,
26
-                    simulation=simulation,
27
-                    position=position,
28
-                ))
29
-    return subjects