gatherer.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import random
  2. import numpy as np
  3. from pathfinding.core.diagonal_movement import DiagonalMovement
  4. from pathfinding.core.grid import Grid
  5. from pathfinding.finder.a_star import AStarFinder
  6. from simulation.board import Board
  7. from simulation.logic.dumb_scouter import DumbScouter
  8. class Gatherer(DumbScouter):
  9. def __init__(self, board, knowledge, x, y, use_diagonal=True, sight_see=-1, light_compute=True):
  10. DumbScouter.__init__(self, board, knowledge, x, y)
  11. self.use_diagonal = use_diagonal
  12. self.light_compute = light_compute
  13. self.sight_see = sight_see if sight_see > 0 else max(self.board.width, self.board.height)
  14. self.goal = None
  15. self.path = []
  16. def get_matrix(self, x0, y0, x1, y1):
  17. width = x1 - x0
  18. height = y1 - y0
  19. matrix = np.zeros((width, height))
  20. for y in range(height):
  21. for x in range(width):
  22. if self.board.get_blob(x0 + x, y0 + y) > 0:
  23. matrix[x, y] = 1 + (Board.MAX_BLOB - self.board.get_blob(x0 + x, y0 + y))
  24. else:
  25. if self.board.is_touched(x0 + x, y0 + y):
  26. matrix[x, y] = Board.MAX_BLOB * 2
  27. else:
  28. matrix[x, y] = 0
  29. return np.transpose(matrix)
  30. def compute_sight_see_goal(self, x0, y0, x1, y1):
  31. if x0 <= self.goal[0] < x1 and y0 <= self.goal[1] < y1:
  32. # Goal in sight_see
  33. return self.goal[0] - x0, self.goal[1] - y0
  34. delta_x = self.x - self.goal[0]
  35. delta_y = self.y - self.goal[1]
  36. t_x = None
  37. if delta_x != 0:
  38. x_collision = x0 if delta_x > 0 else x1 - 1
  39. t_x = (x_collision - self.goal[0]) / delta_x
  40. t_y = None
  41. if delta_y != 0:
  42. y_collision = y0 if delta_y >= 0 else y1 - 1
  43. t_y = (y_collision - self.goal[1]) / delta_y
  44. if t_x is None or not (0 <= t_x <= 1):
  45. t = t_y
  46. elif t_y is None or not (0 <= t_y <= 1):
  47. t = t_x
  48. else:
  49. t = min(t_x, t_y)
  50. symb_goal = (int(self.goal[0] + t * delta_x), int(self.goal[1] + t * delta_y))
  51. found = self.board.is_touched(symb_goal[0], symb_goal[1])
  52. while not found and t <= 1:
  53. inc = 1 / (self.board.width + self.board.height)
  54. t += inc
  55. symb_goal = (int(self.goal[0] + t * delta_x), int(self.goal[1] + t * delta_y))
  56. found = self.board.is_touched(symb_goal[0], symb_goal[1])
  57. return symb_goal[0] - x0, symb_goal[1] - y0
  58. def best_way_to(self):
  59. x0, y0 = max(0, self.x - self.sight_see), max(0, self.y - self.sight_see)
  60. x1, y1 = min(self.board.width, self.x + self.sight_see + 1), min(self.board.height, self.y + self.sight_see + 1)
  61. grid = Grid(matrix=self.get_matrix(x0, y0, x1, y1))
  62. x_goal, y_goal = self.compute_sight_see_goal(x0, y0, x1, y1)
  63. start = grid.node(self.x - x0, self.y - y0)
  64. end = grid.node(x_goal, y_goal)
  65. if self.use_diagonal:
  66. finder = AStarFinder(diagonal_movement=DiagonalMovement.always)
  67. else:
  68. finder = AStarFinder(diagonal_movement=DiagonalMovement.never)
  69. self.path, runs = finder.find_path(start, end, grid)
  70. self.path = self.path[1:]
  71. for i, step in enumerate(self.path):
  72. self.path[i] = (step[0] + x0, step[1] + y0)
  73. def reached(self, goal):
  74. return goal is not None and self.x == goal[0] and self.y == goal[1]
  75. def choose_goal(self):
  76. if len(self.knowledge['food']) == 0:
  77. return None
  78. elif len(self.knowledge['food']) == 1:
  79. if self.reached(self.knowledge['food'][0]):
  80. return None
  81. else:
  82. return self.knowledge['food'][0]
  83. else:
  84. i = random.randrange(len(self.knowledge['food']))
  85. while self.reached(self.knowledge['food'][i]):
  86. i = random.randrange(len(self.knowledge['food']))
  87. return self.knowledge['food'][i]
  88. def reset(self):
  89. self.goal = None
  90. self.path = []
  91. self.x = 0
  92. self.y = 0
  93. def move(self):
  94. # Scouter has no more goal
  95. if self.goal is None or self.goal not in self.knowledge['food']:
  96. self.goal = self.choose_goal()
  97. self.path = []
  98. # No goal
  99. if self.goal is None:
  100. return
  101. # Scouter has no more path to goal
  102. if len(self.path) == 0 or not self.light_compute:
  103. self.best_way_to()
  104. # No path found, search another goal next time
  105. if len(self.path) == 0:
  106. self.goal = None
  107. return
  108. new_pos = self.path[0]
  109. self.path = self.path[1:]
  110. self.x = new_pos[0]
  111. self.y = new_pos[1]
  112. # Scouter reached goal
  113. if self.reached(self.goal):
  114. self.goal = None
  115. self.path = []