simulation.py 5.9KB

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