simulation.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 {
  81. 'finished': True,
  82. }
  83. except KeyError: # TODO: Specialize ? No MoveIntention
  84. return None
  85. class FinishMoveEvent(Event):
  86. def __init__(
  87. self,
  88. subject_id: int,
  89. from_position: typing.Tuple[int, int],
  90. to_position: typing.Tuple[int, int],
  91. gui_action: typing.Any,
  92. *args,
  93. **kwargs
  94. ):
  95. super().__init__(*args, **kwargs)
  96. self.subject_id = subject_id
  97. self.from_position = from_position
  98. self.to_position = to_position
  99. self.gui_action = gui_action
  100. def repr_debug(self) -> str:
  101. return '{}: subject_id:{}, from_position:{} to_position: {}'.format(
  102. type(self).__name__,
  103. self.subject_id,
  104. self.from_position,
  105. self.to_position,
  106. )
  107. class StartMoveEvent(Event):
  108. def __init__(
  109. self,
  110. subject_id: int,
  111. from_position: typing.Tuple[int, int],
  112. to_position: typing.Tuple[int, int],
  113. gui_action: typing.Any,
  114. *args,
  115. **kwargs
  116. ):
  117. super().__init__(*args, **kwargs)
  118. self.subject_id = subject_id
  119. self.from_position = from_position
  120. self.to_position = to_position
  121. self.gui_action = gui_action
  122. def repr_debug(self) -> str:
  123. return '{}: subject_id:{}, from_position:{} to_position: {}'.format(
  124. type(self).__name__,
  125. self.subject_id,
  126. self.from_position,
  127. self.to_position,
  128. )
  129. class MoveToBehaviour(SubjectBehaviour):
  130. move_to_mechanism = MoveToMechanism
  131. use = [move_to_mechanism]
  132. def run(self, data):
  133. move_to_data = data[self.move_to_mechanism]
  134. if move_to_data:
  135. if move_to_data.get('finished'):
  136. return move_to_data
  137. if self._can_move_to_next_step(move_to_data):
  138. move_to_data['reach_next'] = True
  139. return move_to_data
  140. if self._is_fresh_new_step(move_to_data):
  141. move_to_data['reach_next'] = False
  142. return move_to_data
  143. return False
  144. def _can_move_to_next_step(self, move_to_data: dict) -> bool:
  145. raise NotImplementedError()
  146. def _is_fresh_new_step(self, move_to_data: dict) -> bool:
  147. return move_to_data['just_reach'] or move_to_data['initial']
  148. def action(self, data) -> [Event]:
  149. # TODO: MoveToIntention doit être configurable
  150. try:
  151. if data.get('finished'):
  152. self.subject.intentions.remove(MoveToIntention)
  153. return []
  154. move = self.subject.intentions.get(MoveToIntention)
  155. except KeyError: # TODO: Specialize exception
  156. # Action don't exist anymore
  157. return []
  158. move = typing.cast(MoveToIntention, move)
  159. new_path = data['new_path']
  160. if new_path:
  161. move.path = new_path
  162. move.path_progression = -1
  163. previous_position = self.subject.position
  164. new_position = move.path[move.path_progression + 1]
  165. if data['reach_next']:
  166. # TODO: fin de path
  167. move.path_progression += 1
  168. self.subject.position = new_position
  169. move.last_intention_time = time.time()
  170. move.just_reach = True
  171. event = FinishMoveEvent(
  172. self.subject.id,
  173. previous_position,
  174. new_position,
  175. gui_action=move.gui_action,
  176. )
  177. else:
  178. move.just_reach = False
  179. event = StartMoveEvent(
  180. self.subject.id,
  181. previous_position,
  182. new_position,
  183. gui_action=move.gui_action,
  184. )
  185. move.initial = False
  186. # Note: Need to explicitly set to update shared data
  187. self.subject.intentions.set(move)
  188. return [event]