simulation.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # coding: utf-8
  2. import time
  3. import typing
  4. from synergine2.config import Config
  5. from synergine2.simulation import SimulationBehaviour
  6. from synergine2.simulation import Simulation
  7. from synergine2.simulation import Event
  8. from synergine2.simulation import SubjectMechanism
  9. from synergine2.simulation import SubjectBehaviour
  10. from synergine2_xyz.move.intention import MoveToIntention
  11. from synergine2_xyz.simulation import XYZSimulation
  12. class RequestMoveBehaviour(SimulationBehaviour):
  13. move_intention_class = MoveToIntention
  14. @classmethod
  15. def merge_data(cls, new_data, start_data=None):
  16. # TODO: behaviour/Thing dedicated to Gui -> Simulation ?
  17. pass # This behaviour is designed to be launch by terminal
  18. def __init__(
  19. self,
  20. config: Config,
  21. simulation: Simulation,
  22. ):
  23. super().__init__(config, simulation)
  24. self.simulation = typing.cast(XYZSimulation, self.simulation)
  25. def run(self, data):
  26. # TODO: behaviour/Thing dedicated to Gui -> Simulation ?
  27. pass # This behaviour is designed to be launch by terminal
  28. def action(self, data) -> typing.List[Event]:
  29. subject_id = data['subject_id']
  30. move_to = data['move_to']
  31. try:
  32. subject = self.simulation.subjects.index[subject_id]
  33. subject.intentions.set(self.move_intention_class(
  34. move_to,
  35. start_time=time.time(),
  36. gui_action=data['gui_action'],
  37. ))
  38. except KeyError:
  39. # TODO: log error here
  40. pass
  41. return []
  42. class MoveToMechanism(SubjectMechanism):
  43. def run(self):
  44. # TODO: Si move to: Si nouveau: a*, si bloque, a*, sinon rien
  45. # TODO: pourquoi un mechanism plutot que dans run du behaviour ? faire en sorte que lorsque on calcule,
  46. # si un subject est déjà passé par là et qu'il va au même endroit, ne pas recalculer.
  47. try:
  48. # TODO: MoveToIntention doit être configurable
  49. move = self.subject.intentions.get(MoveToIntention)
  50. move = typing.cast(MoveToIntention, move)
  51. new_path = None
  52. if not move.path:
  53. move.path = self.simulation.physics.found_path(
  54. start=self.subject.position,
  55. end=move.move_to,
  56. subject=self.subject,
  57. )
  58. # Note: We are in process, move change will be lost
  59. new_path = move.path
  60. # move.path = []
  61. # new_path = move.path
  62. # for i in range(20):
  63. # move.path.append((
  64. # self.subject.position[0],
  65. # self.subject.position[1] + i,
  66. # ))
  67. next_move = move.path[move.path_progression + 1]
  68. # TODO: fin de path
  69. if not self.simulation.is_possible_position(next_move):
  70. # TODO: refaire le path
  71. new_path = ['...']
  72. return {
  73. 'new_path': new_path,
  74. 'last_intention_time': move.last_intention_time,
  75. 'just_reach': move.just_reach,
  76. 'initial': move.initial,
  77. 'gui_action': move.gui_action,
  78. }
  79. except IndexError: # TODO: Specialize ? No movement left
  80. return None
  81. except KeyError: # TODO: Specialize ? No MoveIntention
  82. return None
  83. class FinishMoveEvent(Event):
  84. def __init__(
  85. self,
  86. subject_id: int,
  87. from_position: typing.Tuple[int, int],
  88. to_position: typing.Tuple[int, int],
  89. gui_action: typing.Any,
  90. *args,
  91. **kwargs
  92. ):
  93. super().__init__(*args, **kwargs)
  94. self.subject_id = subject_id
  95. self.from_position = from_position
  96. self.to_position = to_position
  97. self.gui_action = gui_action
  98. def repr_debug(self) -> str:
  99. return '{}: subject_id:{}, from_position:{} to_position: {}'.format(
  100. type(self).__name__,
  101. self.subject_id,
  102. self.from_position,
  103. self.to_position,
  104. )
  105. class StartMoveEvent(Event):
  106. def __init__(
  107. self,
  108. subject_id: int,
  109. from_position: typing.Tuple[int, int],
  110. to_position: typing.Tuple[int, int],
  111. gui_action: typing.Any,
  112. *args,
  113. **kwargs
  114. ):
  115. super().__init__(*args, **kwargs)
  116. self.subject_id = subject_id
  117. self.from_position = from_position
  118. self.to_position = to_position
  119. self.gui_action = gui_action
  120. def repr_debug(self) -> str:
  121. return '{}: subject_id:{}, from_position:{} to_position: {}'.format(
  122. type(self).__name__,
  123. self.subject_id,
  124. self.from_position,
  125. self.to_position,
  126. )
  127. class MoveToBehaviour(SubjectBehaviour):
  128. move_to_mechanism = MoveToMechanism
  129. use = [move_to_mechanism]
  130. def run(self, data):
  131. move_to_data = data[self.move_to_mechanism]
  132. if move_to_data:
  133. if self._can_move_to_next_step(move_to_data):
  134. move_to_data['reach_next'] = True
  135. return move_to_data
  136. if self._is_fresh_new_step(move_to_data):
  137. move_to_data['reach_next'] = False
  138. return move_to_data
  139. return False
  140. def _can_move_to_next_step(self, move_to_data: dict) -> bool:
  141. raise NotImplementedError()
  142. def _is_fresh_new_step(self, move_to_data: dict) -> bool:
  143. return move_to_data['just_reach'] or move_to_data['initial']
  144. def action(self, data) -> [Event]:
  145. new_path = data['new_path']
  146. # TODO: MoveToIntention doit être configurable
  147. move = self.subject.intentions.get(MoveToIntention)
  148. move = typing.cast(MoveToIntention, move)
  149. if new_path:
  150. move.path = new_path
  151. move.path_progression = -1
  152. previous_position = self.subject.position
  153. new_position = move.path[move.path_progression + 1]
  154. if data['reach_next']:
  155. # TODO: fin de path
  156. move.path_progression += 1
  157. self.subject.position = new_position
  158. move.last_intention_time = time.time()
  159. move.just_reach = True
  160. event = FinishMoveEvent(
  161. self.subject.id,
  162. previous_position,
  163. new_position,
  164. gui_action=move.gui_action,
  165. )
  166. else:
  167. move.just_reach = False
  168. event = StartMoveEvent(
  169. self.subject.id,
  170. previous_position,
  171. new_position,
  172. gui_action=move.gui_action,
  173. )
  174. move.initial = False
  175. # Note: Need to explicitly set to update shared data
  176. self.subject.intentions.set(move)
  177. return [event]