Browse Source

move order

Bastien Sevajol 6 years ago
parent
commit
9bea0faca5

+ 5 - 3
sandbox/engulf/behaviour.py View File

@@ -4,11 +4,13 @@ from random import choice
4 4
 
5 5
 from sandbox.engulf.const import COLLECTION_GRASS, COLLECTION_CELL, COLLECTION_ALIVE, COLLECTION_PREY
6 6
 from sandbox.engulf.exceptions import NotFoundWhereToGo
7
-from synergine2.simulation import SubjectBehaviour, SimulationMechanism, SimulationBehaviour, SubjectBehaviourSelector
8 7
 from synergine2.simulation import Event
8
+from synergine2.simulation import SubjectBehaviour, SimulationMechanism, SimulationBehaviour, SubjectBehaviourSelector
9 9
 from synergine2.utils import ChunkManager
10
-from synergine2.xyz import ProximitySubjectMechanism, DIRECTIONS, DIRECTION_SLIGHTLY, get_direction_from_north_degree
11
-from synergine2.xyz_utils import get_around_positions_of_positions, get_position_for_direction
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
12 14
 
13 15
 # Import for typing hint
14 16
 if False:

+ 1 - 1
sandbox/engulf/exceptions.py View File

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

+ 2 - 2
sandbox/engulf/run.py View File

@@ -31,12 +31,12 @@ from sandbox.engulf.behaviour import GrassGrownUp, GrassSpawn, MoveTo, EatEvent,
31 31
 
32 32
 from synergine2.config import Config
33 33
 from synergine2.log import get_default_logger
34
-from sandbox.engulf.subject import Cell, Grass, PreyCell, PredatorCell
34
+from sandbox.engulf.subject import Grass, PreyCell, PredatorCell
35 35
 from synergine2.core import Core
36 36
 from synergine2.cycle import CycleManager
37 37
 from synergine2.terminals import TerminalManager, Terminal, TerminalPackage
38 38
 from sandbox.engulf.simulation import EngulfSubjects, Engulf
39
-from synergine2.xyz_utils import get_around_positions_of, get_distance_between_points
39
+from synergine2_xyz.utils import get_around_positions_of, get_distance_between_points
40 40
 
41 41
 
42 42
 class GameTerminal(Terminal):

+ 3 - 1
sandbox/engulf/simulation.py View File

@@ -1,7 +1,9 @@
1 1
 # coding: utf-8
2 2
 from sandbox.engulf.behaviour import GrassSpawnBehaviour
3 3
 from sandbox.engulf.subject import Cell, Grass
4
-from synergine2.xyz import XYZSubjects, XYZSubjectMixin, XYZSimulation
4
+from synergine2_xyz.xyz import XYZSubjectMixin
5
+from synergine2_xyz.subjects import XYZSubjects
6
+from synergine2_xyz.simulation import XYZSimulation
5 7
 
6 8
 __author__ = 'bux'
7 9
 

+ 1 - 1
sandbox/engulf/subject.py View File

@@ -4,7 +4,7 @@ from sandbox.engulf.behaviour import GrowUp, SearchGrass, EatGrass, Explore, Cel
4 4
 from sandbox.engulf.const import COLLECTION_CELL, COLLECTION_ALIVE, COLLECTION_EATABLE, COLLECTION_GRASS, \
5 5
     COLLECTION_PREY, COLLECTION_PREDATOR
6 6
 from synergine2.simulation import Subject
7
-from synergine2.xyz import XYZSubjectMixin
7
+from synergine2_xyz.xyz import XYZSubjectMixin
8 8
 
9 9
 
10 10
 class Cell(XYZSubjectMixin, Subject):

+ 3 - 5
sandbox/life_game/run.py View File

@@ -1,9 +1,8 @@
1 1
 # coding: utf-8
2
+import logging
2 3
 import os
3 4
 import sys
4 5
 
5
-import logging
6
-
7 6
 synergine2_ath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../'))
8 7
 sys.path.append(synergine2_ath)
9 8
 
@@ -11,7 +10,7 @@ import collections
11 10
 
12 11
 from synergine2.config import Config
13 12
 from synergine2.log import get_default_logger
14
-from sandbox.life_game.simulation import Cell, LotOfCellsSignalBehaviour, LifeGame, \
13
+from sandbox.life_game.simulation import Cell, LifeGame, \
15 14
     EmptyPositionWithLotOfCellAroundEvent
16 15
 from sandbox.life_game.simulation import Empty
17 16
 from sandbox.life_game.simulation import CellDieEvent
@@ -19,12 +18,11 @@ from sandbox.life_game.simulation import CellBornEvent
19 18
 from sandbox.life_game.utils import get_subjects_from_str_representation
20 19
 from synergine2.core import Core
21 20
 from synergine2.cycle import CycleManager
22
-from synergine2.simulation import Simulation
23 21
 from synergine2.simulation import Event
24 22
 from synergine2.terminals import Terminal
25 23
 from synergine2.terminals import TerminalPackage
26 24
 from synergine2.terminals import TerminalManager
27
-from synergine2.xyz_utils import get_str_representation_from_positions
25
+from synergine2_xyz.utils import get_str_representation_from_positions
28 26
 
29 27
 
30 28
 class SimplePrintTerminal(Terminal):

+ 7 - 6
sandbox/life_game/simulation.py View File

@@ -1,13 +1,14 @@
1 1
 # coding: utf-8
2
-from synergine2.simulation import Subject, SimulationMechanism
3
-from synergine2.simulation import SimulationBehaviour
4 2
 from synergine2.simulation import Event
3
+from synergine2.simulation import SimulationBehaviour
4
+from synergine2.simulation import Subject, SimulationMechanism
5 5
 from synergine2.simulation import SubjectBehaviour
6 6
 from synergine2.utils import ChunkManager
7
-from synergine2.xyz import ProximitySubjectMechanism, ProximityMixin
8
-from synergine2.xyz import XYZSubjectMixin
9
-from synergine2.xyz import XYZSimulation
10
-from synergine2.xyz_utils import get_around_positions_of_positions, get_min_and_max
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
11 12
 
12 13
 COLLECTION_CELL = 'COLLECTION_CELL'  # Collections of Cell type
13 14
 

+ 3 - 3
sandbox/life_game/utils.py View File

@@ -1,9 +1,9 @@
1 1
 # coding: utf-8
2
-from sandbox.life_game.simulation import Empty
3 2
 from sandbox.life_game.simulation import Cell
3
+from sandbox.life_game.simulation import Empty
4 4
 from synergine2.simulation import Simulation
5
-from synergine2.xyz import XYZSubjects
6
-from synergine2.xyz_utils import get_positions_from_str_representation
5
+from synergine2_xyz.subjects import XYZSubjects
6
+from synergine2_xyz.utils import get_positions_from_str_representation
7 7
 
8 8
 
9 9
 def get_subjects_from_str_representation(

+ 4 - 5
sandbox/tile/simulation/base.py View File

@@ -1,8 +1,7 @@
1 1
 # coding: utf-8
2
-from synergine2.simulation import Subject
3
-from synergine2.xyz import XYZSimulation
4
-from synergine2.xyz import XYZSubjectMixin
5
-from synergine2.xyz import XYZSubjects
2
+from synergine2_xyz.simulation import XYZSimulation
3
+from synergine2_xyz.xyz import XYZSubject
4
+from synergine2_xyz.subjects import XYZSubjects
6 5
 
7 6
 
8 7
 class TileStrategySimulation(XYZSimulation):
@@ -15,5 +14,5 @@ class TileStrategySubjects(XYZSubjects):
15 14
     pass
16 15
 
17 16
 
18
-class BaseSubject(XYZSubjectMixin, Subject):
17
+class BaseSubject(XYZSubject):
19 18
     pass

+ 5 - 0
synergine2/simulation.py View File

@@ -7,6 +7,10 @@ from synergine2.config import Config
7 7
 from synergine2.utils import get_mechanisms_classes
8 8
 
9 9
 
10
+class Intention(object):
11
+    pass
12
+
13
+
10 14
 class Subject(BaseObject):
11 15
     collections = []
12 16
     behaviours_classes = []
@@ -25,6 +29,7 @@ class Subject(BaseObject):
25 29
         self.simulation = simulation
26 30
         self.behaviours = {}
27 31
         self.mechanisms = {}
32
+        self.intentions = []  # type: typing.List[Intention]
28 33
         self.behaviour_selector = None  # type: SubjectBehaviourSelector
29 34
         if self.behaviour_selector_class:
30 35
             self.behaviour_selector = self.behaviour_selector_class()

+ 0 - 21
synergine2_cocos2d/event.py View File

@@ -1,21 +0,0 @@
1
-# coding: utf-8
2
-
3
-"""
4
-WARNING: Do not import cocos/pyglet stuff here: cocos/pyglet modules must be loaded inside gui process.
5
-"""
6
-import typing
7
-
8
-from synergine2.simulation import Event
9
-
10
-
11
-class GuiRequestMoveEvent(Event):
12
-    def __init__(
13
-        self,
14
-        subject_id: int,
15
-        move_to_position: typing.Tuple[int, int],
16
-        *args,
17
-        **kwargs
18
-    ) -> None:
19
-        super().__init__(*args, **kwargs)
20
-        self.subject_id = subject_id
21
-        self.move_to_position = move_to_position

+ 5 - 5
synergine2_cocos2d/gui.py View File

@@ -4,8 +4,8 @@ import weakref
4 4
 from math import floor
5 5
 
6 6
 import pyglet
7
-from pyglet.window import mouse
8 7
 from pyglet.window import key
8
+from pyglet.window import mouse
9 9
 
10 10
 import cocos
11 11
 from cocos import collision_model
@@ -15,17 +15,17 @@ from synergine2.config import Config
15 15
 from synergine2.log import SynergineLogger
16 16
 from synergine2.terminals import Terminal
17 17
 from synergine2.terminals import TerminalPackage
18
-from synergine2.xyz import XYZSubjectMixin
19 18
 from synergine2_cocos2d.actor import Actor
20
-from synergine2_cocos2d.exception import OuterWorldPosition
21 19
 from synergine2_cocos2d.exception import InteractionNotFound
22
-from synergine2_cocos2d.gl import rectangle_positions_type
20
+from synergine2_cocos2d.exception import OuterWorldPosition
23 21
 from synergine2_cocos2d.gl import draw_rectangle
22
+from synergine2_cocos2d.gl import rectangle_positions_type
24 23
 from synergine2_cocos2d.interaction import InteractionManager
25 24
 from synergine2_cocos2d.layer import LayerManager
26
-from synergine2_cocos2d.middleware import TMXMiddleware
27 25
 from synergine2_cocos2d.middleware import MapMiddleware
26
+from synergine2_cocos2d.middleware import TMXMiddleware
28 27
 from synergine2_cocos2d.user_action import UserAction
28
+from synergine2_xyz.xyz import XYZSubjectMixin
29 29
 
30 30
 
31 31
 class GridManager(object):

+ 12 - 7
synergine2_cocos2d/interaction.py View File

@@ -1,10 +1,12 @@
1 1
 # coding: utf-8
2 2
 import typing
3 3
 
4
+from synergine2_xyz.move import RequestMoveBehaviour
5
+
4 6
 from synergine2.config import Config
5 7
 from synergine2.log import SynergineLogger
6
-from synergine2.terminals import Terminal, TerminalPackage
7
-from synergine2_cocos2d.event import GuiRequestMoveEvent
8
+from synergine2.terminals import Terminal
9
+from synergine2.terminals import TerminalPackage
8 10
 from synergine2_cocos2d.exception import InteractionNotFound
9 11
 from synergine2_cocos2d.gl import draw_line
10 12
 from synergine2_cocos2d.layer import LayerManager
@@ -70,6 +72,7 @@ class Interaction(object):
70 72
 
71 73
 class MoveActorInteraction(Interaction):
72 74
     gui_action = UserAction.ORDER_MOVE
75
+    request_move_behaviour_class = RequestMoveBehaviour
73 76
 
74 77
     def draw_pending(self) -> None:
75 78
             for actor in self.layer_manager.edit_layer.selection:
@@ -84,7 +87,7 @@ class MoveActorInteraction(Interaction):
84 87
 
85 88
     def get_package_for_terminal(self) -> TerminalPackage:
86 89
         # TODO: MoveEvent ?
87
-        events = []
90
+        actions = []
88 91
         mouse_grid_position = self.layer_manager.grid_manager.get_grid_position(
89 92
             self.layer_manager.scrolling_manager.screen_to_world(
90 93
                 *self.layer_manager.edit_layer.screen_mouse,
@@ -92,11 +95,13 @@ class MoveActorInteraction(Interaction):
92 95
         )
93 96
 
94 97
         for actor in self.layer_manager.edit_layer.selection:
95
-            events.append(GuiRequestMoveEvent(
96
-                subject_id=actor.subject.id,
97
-                move_to_position=mouse_grid_position,
98
+            actions.append((
99
+                self.request_move_behaviour_class, {
100
+                    'subject_id': actor.subject.id,
101
+                    'move_to': mouse_grid_position,
102
+                }
98 103
             ))
99 104
 
100 105
         return TerminalPackage(
101
-            events=events
106
+            simulation_actions=actions,
102 107
         )

+ 1 - 0
synergine2_xyz/__init__.py View File

@@ -0,0 +1 @@
1
+# coding: utf-8

+ 12 - 0
synergine2_xyz/mechanism.py View File

@@ -0,0 +1,12 @@
1
+# coding: utf-8
2
+from synergine2.simulation import SubjectMechanism
3
+from synergine2_xyz.xyz import ProximityMixin
4
+
5
+
6
+class ProximitySubjectMechanism(ProximityMixin, SubjectMechanism):
7
+    def run(self):
8
+        return self.get_for_position(
9
+            position=self.subject.position,
10
+            simulation=self.simulation,
11
+            exclude_subject=self.subject,
12
+        )

+ 60 - 0
synergine2_xyz/move.py View File

@@ -0,0 +1,60 @@
1
+# coding: utf-8
2
+import typing
3
+
4
+from synergine2.config import Config
5
+from synergine2.simulation import SimulationBehaviour, SubjectBehaviour
6
+from synergine2.simulation import Intention
7
+from synergine2.simulation import Simulation
8
+from synergine2.simulation import Event
9
+from synergine2_xyz.simulation import XYZSimulation
10
+
11
+
12
+class MoveToIntention(Intention):
13
+    def __init__(self, move_to: typing.Tuple[int, int]) -> None:
14
+        self.move_to = move_to
15
+        self.path = []  # type: typing.List[typing.Tuple[int, int]]
16
+        self.path_progression = None  # type: int
17
+
18
+
19
+class RequestMoveBehaviour(SimulationBehaviour):
20
+    move_intention_class = MoveToIntention
21
+
22
+    @classmethod
23
+    def merge_data(cls, new_data, start_data=None):
24
+        # TODO: behaviour/Thing dedicated to Gui -> Simulation ?
25
+        pass  # This behaviour is designed to be launch by terminal
26
+
27
+    def __init__(
28
+        self,
29
+        config: Config,
30
+        simulation: Simulation,
31
+    ):
32
+        super().__init__(config, simulation)
33
+        self.simulation = typing.cast(XYZSimulation, self.simulation)
34
+
35
+    def run(self, data):
36
+        # TODO: behaviour/Thing dedicated to Gui -> Simulation ?
37
+        pass  # This behaviour is designed to be launch by terminal
38
+
39
+    def action(self, data) -> typing.List[Event]:
40
+        subject_id = data['subject_id']
41
+        move_to = data['move_to']
42
+
43
+        try:
44
+            subject = self.simulation.subjects.index[subject_id]
45
+            subject.intentions.append(self.move_intention_class(move_to))
46
+        except KeyError:
47
+            # TODO: log error here
48
+            pass
49
+
50
+        return []
51
+
52
+
53
+class MoveToBehaviour(SubjectBehaviour):
54
+    def run(self, data):
55
+        # TODO: progresser dans l'intention (comment implementer ça?)
56
+        raise NotImplementedError()
57
+
58
+    def action(self, data) -> [Event]:
59
+        # TODO: effectuer un move vers une nouvelle position ou faire progresser "l'entre-deux"
60
+        raise NotImplementedError()

+ 16 - 0
synergine2_xyz/simulation.py View File

@@ -0,0 +1,16 @@
1
+# coding: utf-8
2
+import typing
3
+
4
+from synergine2.simulation import Simulation as BaseSimulation
5
+from synergine2_xyz.xyz import XYZSubject
6
+from synergine2_xyz.subjects import XYZSubjects
7
+
8
+
9
+class XYZSimulation(BaseSimulation):
10
+    accepted_subject_class = XYZSubjects
11
+
12
+    def is_possible_subject_position(self, subject: XYZSubject, position: tuple) -> bool:
13
+        return self.is_possible_position(position)
14
+
15
+    def is_possible_position(self, position: tuple) -> bool:
16
+        return True

+ 36 - 0
synergine2_xyz/subjects.py View File

@@ -0,0 +1,36 @@
1
+# coding: utf-8
2
+from synergine2.simulation import Subjects
3
+from synergine2_xyz.xyz import XYZSubjectMixin, PositionNotPossible
4
+
5
+
6
+class XYZSubjects(Subjects):
7
+    def __init__(self, *args, **kwargs):
8
+        super().__init__(*args, **kwargs)
9
+        # TODO: accept multiple subjects as same position
10
+        # TODO: init xyz with given list
11
+        self.xyz = {}
12
+
13
+    def have_to_check_position_is_possible(self) -> bool:
14
+        return True
15
+
16
+    def remove(self, value: XYZSubjectMixin):
17
+        super().remove(value)
18
+
19
+        try:
20
+            self.xyz.get(value.position, []).remove(value)
21
+            if not self.xyz[value.position]:
22
+                del self.xyz[value.position]
23
+        except ValueError:
24
+            pass
25
+
26
+    def append(self, p_object: XYZSubjectMixin):
27
+        super().append(p_object)
28
+
29
+        if self.have_to_check_position_is_possible() \
30
+           and not self.simulation.is_possible_subject_position(p_object, p_object.position):
31
+            raise PositionNotPossible('Position {} for {} is not possible'.format(
32
+                str(p_object.position),
33
+                str(p_object),
34
+            ))
35
+
36
+        self.xyz.setdefault(p_object.position, []).append(p_object)

synergine2/xyz_utils.py → synergine2_xyz/utils.py View File

@@ -1,8 +1,8 @@
1 1
 # coding: utf-8
2
-from math import sqrt
3 2
 import collections
3
+from math import sqrt
4 4
 
5
-from synergine2.xyz import DIRECTION_MODIFIERS
5
+from synergine2_xyz.xyz import DIRECTION_MODIFIERS
6 6
 
7 7
 
8 8
 def get_positions_from_str_representation(str_representation):

synergine2/xyz.py → synergine2_xyz/xyz.py View File

@@ -1,12 +1,10 @@
1 1
 # coding: utf-8
2
-from math import sqrt
3
-from math import degrees
4 2
 from math import acos
3
+from math import degrees
4
+from math import sqrt
5 5
 
6 6
 from synergine2.exceptions import SynergineException
7
-from synergine2.simulation import SubjectMechanism, Subjects, Subject
8
-from synergine2.simulation import Simulation as BaseSimulation
9
-
7
+from synergine2.simulation import Subject
10 8
 
11 9
 """
12 10
 
@@ -133,6 +131,10 @@ class XYZSubjectMixin(object, metaclass=XYZSubjectMixinMetaClass):
133 131
         self._position = value
134 132
 
135 133
 
134
+class XYZSubject(XYZSubjectMixin, Subject):
135
+    pass
136
+
137
+
136 138
 class ProximityMixin(object):
137 139
     distance = 1
138 140
     feel_collections = [COLLECTION_XYZ]
@@ -185,7 +187,7 @@ class ProximityMixin(object):
185 187
 
186 188
     @classmethod
187 189
     def get_distance_of(cls, position, subject: XYZSubjectMixin):
188
-        from synergine2.xyz_utils import get_distance_between_points  # cyclic import
190
+        from synergine2_xyz.utils import get_distance_between_points  # cyclic import
189 191
         return get_distance_between_points(
190 192
             position,
191 193
             subject.position,
@@ -195,58 +197,6 @@ class ProximityMixin(object):
195 197
         return True
196 198
 
197 199
 
198
-class ProximitySubjectMechanism(ProximityMixin, SubjectMechanism):
199
-    def run(self):
200
-        return self.get_for_position(
201
-            position=self.subject.position,
202
-            simulation=self.simulation,
203
-            exclude_subject=self.subject,
204
-        )
205
-
206
-
207
-class XYZSubjects(Subjects):
208
-    def __init__(self, *args, **kwargs):
209
-        super().__init__(*args, **kwargs)
210
-        # TODO: accept multiple subjects as same position
211
-        # TODO: init xyz with given list
212
-        self.xyz = {}
213
-
214
-    def have_to_check_position_is_possible(self) -> bool:
215
-        return True
216
-
217
-    def remove(self, value: XYZSubjectMixin):
218
-        super().remove(value)
219
-
220
-        try:
221
-            self.xyz.get(value.position, []).remove(value)
222
-            if not self.xyz[value.position]:
223
-                del self.xyz[value.position]
224
-        except ValueError:
225
-            pass
226
-
227
-    def append(self, p_object: XYZSubjectMixin):
228
-        super().append(p_object)
229
-
230
-        if self.have_to_check_position_is_possible() \
231
-           and not self.simulation.is_possible_subject_position(p_object, p_object.position):
232
-            raise PositionNotPossible('Position {} for {} is not possible'.format(
233
-                str(p_object.position),
234
-                str(p_object),
235
-            ))
236
-
237
-        self.xyz.setdefault(p_object.position, []).append(p_object)
238
-
239
-
240
-class XYZSimulation(BaseSimulation):
241
-    accepted_subject_class = XYZSubjects
242
-
243
-    def is_possible_subject_position(self, subject: XYZSubjectMixin, position: tuple) -> bool:
244
-        return self.is_possible_position(position)
245
-
246
-    def is_possible_position(self, position: tuple) -> bool:
247
-        return True
248
-
249
-
250 200
 def get_direction_from_north_degree(degree: float):
251 201
     for range, direction in DIRECTION_FROM_NORTH_DEGREES.items():
252 202
         if range[0] <= degree <= range[1]:

+ 4 - 3
tests/test_life_game.py View File

@@ -1,14 +1,15 @@
1 1
 # coding: utf-8
2 2
 import collections
3
+
3 4
 from sandbox.life_game.simulation import Cell
4 5
 from sandbox.life_game.simulation import Empty
5 6
 from sandbox.life_game.utils import get_subjects_from_str_representation
6 7
 from synergine2.config import Config
7 8
 from synergine2.cycle import CycleManager
8 9
 from synergine2.log import SynergineLogger
9
-from synergine2.xyz import XYZSubjects
10
-from synergine2.xyz import XYZSimulation
11
-from synergine2.xyz_utils import get_str_representation_from_positions
10
+from synergine2_xyz.simulation import XYZSimulation
11
+from synergine2_xyz.subjects import XYZSubjects
12
+from synergine2_xyz.utils import get_str_representation_from_positions
12 13
 from tests import BaseTest
13 14
 from tests import str_kwargs
14 15
 

+ 6 - 6
tests/test_xyz.py View File

@@ -2,12 +2,12 @@
2 2
 # -*- coding: utf-8 -*-
3 3
 from synergine2.config import Config
4 4
 from synergine2.simulation import Subject
5
-from synergine2.xyz import ProximitySubjectMechanism
6
-from synergine2.xyz import XYZSubjects
7
-from synergine2.xyz import XYZSimulation
8
-from synergine2.xyz import XYZSubjectMixin
9
-from synergine2.xyz_utils import get_positions_from_str_representation
10
-from synergine2.xyz_utils import get_str_representation_from_positions
5
+from synergine2_xyz.mechanism import ProximitySubjectMechanism
6
+from synergine2_xyz.simulation import XYZSimulation
7
+from synergine2_xyz.xyz import XYZSubjectMixin
8
+from synergine2_xyz.subjects import XYZSubjects
9
+from synergine2_xyz.utils import get_positions_from_str_representation
10
+from synergine2_xyz.utils import get_str_representation_from_positions
11 11
 from tests import BaseTest
12 12
 from tests import str_kwargs
13 13