MoveAction.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. from synergine.synergy.event.Action import Action
  2. from intelligine.synergy.event.move.MoveEvent import MoveEvent
  3. from random import randint, choice, randrange
  4. from xyzworld.cst import POSITION
  5. from intelligine.cst import PREVIOUS_DIRECTION, BLOCKED_SINCE, MOVE_MODE, MOVE_MODE_EXPLO
  6. from intelligine.cst import COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING
  7. from intelligine.synergy.event.move.direction import directions_same_level, directions_modifiers, directions_slighty
  8. from intelligine.core.exceptions import NoPheromone, BestPheromoneHere
  9. from intelligine.simulation.pheromone.DirectionPheromone import DirectionPheromone
  10. class MoveAction(Action):
  11. _listen = MoveEvent
  12. def __init__(self, object_id, parameters):
  13. super().__init__(object_id, parameters)
  14. self._move_to_point = None
  15. self._move_to_direction = None
  16. def prepare(self, context):
  17. object_point = context.metas.value.get(POSITION, self._object_id)
  18. try:
  19. direction = self._get_direction_with_pheromones(context, object_point)
  20. except NoPheromone:
  21. direction = self._get_random_direction(context)
  22. move_to_point = self._get_point_for_direction(object_point, direction)
  23. if self._direction_point_is_possible(context, move_to_point):
  24. self._move_to_point = move_to_point
  25. self._move_to_direction = direction
  26. else:
  27. # TODO: mettre self._dont_move = True ?
  28. pass
  29. def _get_direction_with_pheromones(self, context, object_point):
  30. # TODO: Placer directnement pheromone type dans les metas
  31. object_movement_mode = context.metas.value.get(MOVE_MODE, self._object_id)
  32. pheromone_type = DirectionPheromone.get_pheromone_type_for_move_mode(object_movement_mode)
  33. try:
  34. direction = self._get_pheromone_direction_for_point(context, object_point, pheromone_type)
  35. except NoPheromone:
  36. direction = self._get_direction_of_pheromone(context, object_point, pheromone_type)
  37. return direction
  38. @staticmethod
  39. def _get_pheromone_direction_for_point(context, point, pheromone_type):
  40. return DirectionPheromone.get_direction_for_point(context, point, pheromone_type)
  41. @staticmethod
  42. def _get_direction_of_pheromone(context, point, pheromone_type):
  43. search_pheromone_distance = 1 # TODO: config
  44. search_pheromone_in_points = context.get_arround_points_of(point, distance=search_pheromone_distance)
  45. try:
  46. # TODO: ? Avoir plutot un DirectionPheromone.get_best_pheromone_direction_in ?
  47. best_pheromone_direction = DirectionPheromone.get_best_pheromone_direction_in(context,
  48. point,
  49. search_pheromone_in_points,
  50. pheromone_type)
  51. return best_pheromone_direction
  52. except NoPheromone as err:
  53. raise err
  54. # def _get_random_direction_point(self, context, reference_point):
  55. # z, x, y = reference_point
  56. # direction_name = self._get_random_direction_name(context)
  57. # directions_modifier = directions_modifiers[direction_name]
  58. # new_position = (z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2])
  59. # return (direction_name, new_position)
  60. def _get_random_direction(self, context):
  61. try:
  62. blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
  63. except KeyError:
  64. blocked_since = 0
  65. direction_name = None
  66. if blocked_since <= 3: #TODO: config
  67. try:
  68. previous_direction = context.metas.value.get(PREVIOUS_DIRECTION, self._object_id)
  69. # TODO: Faut mettre ca en plus propre (proba d'aller tou droit, config, etc)
  70. if randrange(100) < 75: # 75% de change d'aller tout droit
  71. # Dans le futur: les fourmis vont moins tout droit quand elle se croient et se touche
  72. return previous_direction
  73. directions_list = directions_slighty[previous_direction]
  74. # TODO: TMP tant que 1 niveau (z)
  75. directions_list = [direction for direction in directions_list if direction > 9 and direction < 19]
  76. direction_name = choice(directions_list)
  77. except KeyError:
  78. pass
  79. if not direction_name:
  80. direction_name = randint(directions_same_level[0], directions_same_level[1])
  81. return direction_name
  82. @staticmethod
  83. def _get_point_for_direction(reference_point, direction):
  84. # TODO: mettre une fonction cote direction.py pour appliquer le modifier.
  85. z, x, y = reference_point
  86. directions_modifier = directions_modifiers[direction]
  87. return z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2]
  88. @staticmethod
  89. def _direction_point_is_possible(context, direction_point):
  90. return context.position_is_penetrable(direction_point)
  91. def run(self, obj, context, synergy_manager):
  92. if self._move_to_point is not None and self._move_to_direction != 14: # TODO: il ne faut pas choisir une direction 14.
  93. obj.set_position(self._move_to_point)
  94. #direction_from = directions_opposites[self._move_to_direction]
  95. #obj.set_direction_from(direction_from)
  96. context.metas.value.set(PREVIOUS_DIRECTION, self._object_id, self._move_to_direction)
  97. context.metas.value.set(BLOCKED_SINCE, self._object_id, 0)
  98. self._appose_pheromone(obj, context)
  99. # TEST: le temps de tout tester
  100. if self._move_to_point == obj.get_colony().get_start_position() and obj.is_carrying():
  101. obj_transported = obj.get_carried()
  102. obj_transported.set_carried_by(None)
  103. obj.put_carry(obj_transported, (-1, 0, 0))
  104. obj.get_brain().switch_to_mode(MOVE_MODE_EXPLO)
  105. context.metas.collections.add_remove(obj.get_id(),
  106. COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING)
  107. # TMP: Devra etre un event et une action
  108. # if self._move_to_point == (0, 5, 5): # position de depart
  109. # if len(obj._carried):
  110. # obj_transported = obj.get_carried()
  111. # obj_transported.set_carried_by(None)
  112. # obj.put_carry(obj_transported, (-1, 5, 5))
  113. # context.metas.collections.add_remove(obj.get_id(), COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING)
  114. # obj.set_movement_mode(MOVE_MODE_EXPLO)
  115. else:
  116. try:
  117. blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
  118. except:
  119. blocked_since = 0
  120. context.metas.value.set(BLOCKED_SINCE, self._object_id, blocked_since+1)
  121. # def _get_pheromone_direction_point(self, context, object_point):
  122. # try:
  123. # blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
  124. # except KeyError:
  125. # blocked_since = 0
  126. # if blocked_since > 3:
  127. # raise NoPheromoneMove()
  128. # # Si on explore, on cherche pheromone d'explo
  129. # # si on rentre a home, on cherche pheromone d'home...
  130. # # TODO: code arrache
  131. # object_movement_mode = context.metas.value.get(MOVE_MODE, self._object_id)
  132. # if object_movement_mode == MOVE_MODE_EXPLO:
  133. # pheromone_direction_type = PHEROMON_DIR_EXPLO
  134. # elif object_movement_mode == MOVE_MODE_GOHOME:
  135. # pheromone_direction_type = PHEROMON_DIR_HOME
  136. #
  137. # sniff_points = context.get_arround_points_of(object_point, distance=0)
  138. # # Faire un compile des infos de pheromones
  139. #
  140. # directions = {}
  141. # for sniff_point in sniff_points:
  142. # info = context.pheromones().get_info(sniff_point,
  143. # [PHEROMON_DIRECTION, pheromone_direction_type],
  144. # allow_empty=True,
  145. # empty_value={})
  146. # for direction in info:
  147. # if direction not in directions:
  148. # directions[direction] = info[direction]
  149. # else:
  150. # directions[direction] += info[direction]
  151. # if len(directions):
  152. # sorted_directions = sorted(directions.items(), key=operator.itemgetter(1))
  153. # sorted_directions.reverse()
  154. # #best_direction_name = sorted_directions[0][0]
  155. # best_direction_level = sorted_directions[0][1]
  156. # best_direction_names = [direction for direction in directions \
  157. # if directions[direction] == best_direction_level]
  158. # # Si plusieurs best directions, choisir mm direction que la precedente
  159. # # si y a pas, au hasard.
  160. # last_dir_name = context.metas.value.get(PREVIOUS_DIRECTION, self._object_id)
  161. # if last_dir_name in best_direction_names:
  162. # direction_name = last_dir_name
  163. # else:
  164. # direction_name = choice(best_direction_names)
  165. #
  166. # # DRY
  167. # z, x, y = object_point
  168. # directions_modifier = directions_modifiers[direction_name]
  169. # new_position = (z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2])
  170. # return (direction_name, new_position)
  171. #
  172. # pass
  173. # raise NoPheromoneMove()
  174. def _appose_pheromone(self, obj, context):
  175. # TODO: Cette action de pheromone doit etre une surcharge de Move afin d'avoir une Action Move generique.
  176. obj.get_brain().host_moved()
  177. try:
  178. DirectionPheromone.appose(context,
  179. obj.get_position(),
  180. obj.get_movement_pheromone_gland().get_movement_molecules())
  181. except BestPheromoneHere as best_pheromone_here:
  182. obj.get_brain().set_distance_from_objective(best_pheromone_here.get_best_distance())