simulation.py 6.1KB

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