MoveAction.py 10KB

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