behaviour.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # coding: utf-8
  2. import typing
  3. from random import choice
  4. from sandbox.engulf.const import COLLECTION_GRASS
  5. from synergine2.simulation import SubjectBehaviour, SimulationMechanism, SimulationBehaviour, SubjectBehaviourSelector
  6. from synergine2.simulation import Event
  7. from synergine2.utils import ChunkManager
  8. from synergine2.xyz import ProximitySubjectMechanism, DIRECTIONS, DIRECTION_SLIGHTLY
  9. from synergine2.xyz_utils import get_around_positions_of_positions, get_around_positions_of, get_position_for_direction
  10. class GrassGrownUp(Event):
  11. def __init__(self, subject_id, density, *args, **kwargs):
  12. super().__init__(*args, **kwargs)
  13. self.subject_id = subject_id
  14. self.density = density
  15. def repr_debug(self) -> str:
  16. return '{}: subject_id:{}, density:{}'.format(
  17. self.__class__.__name__,
  18. self.subject_id,
  19. self.density,
  20. )
  21. class GrassSpawn(Event):
  22. def __init__(self, subject_id, position, density, *args, **kwargs):
  23. super().__init__(*args, **kwargs)
  24. self.subject_id = subject_id
  25. self.position = position
  26. self.density = density
  27. def repr_debug(self) -> str:
  28. return '{}: subject_id:{}, position:{}, density:{}'.format(
  29. self.__class__.__name__,
  30. self.subject_id,
  31. self.position,
  32. self.density,
  33. )
  34. class GrassSpotablePositionsMechanism(SimulationMechanism):
  35. parallelizable = True
  36. def run(self, process_number: int=None, process_count: int=None):
  37. chunk_manager = ChunkManager(process_count)
  38. positions = list(self.simulation.subjects.grass_xyz.keys())
  39. positions_chunks = chunk_manager.make_chunks(positions)
  40. spotables = []
  41. for position in positions_chunks[process_number]:
  42. arounds = get_around_positions_of_positions(position)
  43. from_subject = self.simulation.subjects.grass_xyz[position]
  44. around_data = {
  45. 'from_subject': from_subject,
  46. 'around': [],
  47. }
  48. for around in arounds:
  49. if around not in self.simulation.subjects.grass_xyz:
  50. around_data['around'].append(around)
  51. if around_data['around']:
  52. spotables.append(around_data)
  53. return spotables
  54. class GrowUp(SubjectBehaviour):
  55. frequency = 20
  56. def run(self, data):
  57. return True
  58. def action(self, data) -> [Event]:
  59. self.subject.density += 1
  60. return [GrassGrownUp(
  61. self.subject.id,
  62. self.subject.density,
  63. )]
  64. class GrassSpawnBehaviour(SimulationBehaviour):
  65. frequency = 100
  66. use = [GrassSpotablePositionsMechanism]
  67. def run(self, data):
  68. spawns = []
  69. for around_data in data[GrassSpotablePositionsMechanism]:
  70. from_subject = around_data['from_subject']
  71. arounds = around_data['around']
  72. if from_subject.density >= 40:
  73. spawns.extend(arounds)
  74. return spawns
  75. @classmethod
  76. def merge_data(cls, new_data, start_data=None):
  77. start_data = start_data or []
  78. start_data.extend(new_data)
  79. return start_data
  80. def action(self, data) -> [Event]:
  81. from sandbox.engulf.subject import Grass # cyclic
  82. events = []
  83. for position in data:
  84. if position not in list(self.simulation.subjects.grass_xyz.keys()):
  85. new_grass = Grass(
  86. self.simulation,
  87. position=position,
  88. density=20,
  89. )
  90. self.simulation.subjects.append(new_grass)
  91. events.append(GrassSpawn(
  92. new_grass.id,
  93. new_grass.position,
  94. new_grass.density,
  95. ))
  96. return events
  97. class EatableDirectProximityMechanism(ProximitySubjectMechanism):
  98. distance = 1.41 # distance when on angle
  99. feel_collections = [COLLECTION_GRASS]
  100. class MoveTo(Event):
  101. def __init__(self, subject_id: int, position: tuple, *args, **kwargs):
  102. super().__init__(*args, **kwargs)
  103. self.subject_id = subject_id
  104. self.position = position
  105. def repr_debug(self) -> str:
  106. return '{}: subject_id:{}, position:{}'.format(
  107. type(self).__name__,
  108. self.subject_id,
  109. self.position,
  110. )
  111. class SearchFood(SubjectBehaviour):
  112. """
  113. Si une nourriture a une case de distance et cellule non rassasié, move dans sa direction.
  114. """
  115. use = [EatableDirectProximityMechanism]
  116. def run(self, data):
  117. pass
  118. class Eat(SubjectBehaviour):
  119. """
  120. Prduit un immobilisme si sur une case de nourriture, dans le cas ou la cellule n'est as rassasié.
  121. """
  122. def run(self, data):
  123. pass
  124. class Explore(SubjectBehaviour):
  125. """
  126. Produit un mouvement au hasard (ou un immobilisme)
  127. """
  128. use = []
  129. def action(self, data) -> [Event]:
  130. direction = self.get_random_direction()
  131. position = get_position_for_direction(self.subject.position, direction)
  132. self.subject.position = position
  133. self.subject.previous_direction = direction
  134. return [MoveTo(self.subject.id, position)]
  135. def run(self, data):
  136. return True # for now, want move every time
  137. def get_random_direction(self):
  138. if not self.subject.previous_direction:
  139. return choice(DIRECTIONS)
  140. return choice(DIRECTION_SLIGHTLY[self.subject.previous_direction])
  141. class CellBehaviourSelector(SubjectBehaviourSelector):
  142. # If behaviour in sublist, only one be kept in sublist
  143. behaviour_hierarchy = ( # TODO: refact it
  144. (
  145. Eat,
  146. SearchFood,
  147. Explore,
  148. ),
  149. )
  150. def reduce_behaviours(
  151. self,
  152. behaviours: typing.Dict[typing.Type[SubjectBehaviour], dict],
  153. ) -> typing.Dict[typing.Type[SubjectBehaviour], dict]:
  154. return behaviours # TODO: code it