simulation.py 6.2KB

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