import random import numpy as np from pathfinding.core.diagonal_movement import DiagonalMovement from pathfinding.core.grid import Grid from pathfinding.finder.a_star import AStarFinder from simulation.board import Board from simulation.logic.dumb_scouter import DumbScouter class Gatherer(DumbScouter): def __init__(self, board, knowledge, x, y, use_diagonal=True, sightline=-1, light_compute=True): DumbScouter.__init__(self, board, knowledge, x, y) self.use_diagonal = use_diagonal self.light_compute = light_compute self.sight_see = sightline if sightline > 0 else max(self.board.width, self.board.height) self.goal = None self.path = [] def get_matrix(self, x0, y0, x1, y1): width = x1 - x0 height = y1 - y0 matrix = np.zeros((width, height)) for y in range(height): for x in range(width): if self.board.get_blob(x0 + x, y0 + y) > 0: matrix[x, y] = 1 + (Board.MAX_BLOB - self.board.get_blob(x0 + x, y0 + y)) else: if self.board.is_touched(x0 + x, y0 + y): matrix[x, y] = Board.MAX_BLOB * 2 else: matrix[x, y] = 0 return np.transpose(matrix) def compute_sight_see_goal(self, x0, y0, x1, y1): if x0 <= self.goal[0] < x1 and y0 <= self.goal[1] < y1: # Goal in sight_see return self.goal[0] - x0, self.goal[1] - y0 delta_x = self.x - self.goal[0] delta_y = self.y - self.goal[1] t_x = None if delta_x != 0: x_collision = x0 if delta_x > 0 else x1 - 1 t_x = (x_collision - self.goal[0]) / delta_x t_y = None if delta_y != 0: y_collision = y0 if delta_y >= 0 else y1 - 1 t_y = (y_collision - self.goal[1]) / delta_y if t_x is None or not (0 <= t_x <= 1): t = t_y elif t_y is None or not (0 <= t_y <= 1): t = t_x else: t = min(t_x, t_y) symb_goal = (int(self.goal[0] + t * delta_x), int(self.goal[1] + t * delta_y)) found = self.board.is_touched(symb_goal[0], symb_goal[1]) while not found and t <= 1: inc = 1 / (self.board.width + self.board.height) t += inc symb_goal = (int(self.goal[0] + t * delta_x), int(self.goal[1] + t * delta_y)) found = self.board.is_touched(symb_goal[0], symb_goal[1]) return symb_goal[0] - x0, symb_goal[1] - y0 def best_way_to(self): x0, y0 = max(0, self.x - self.sight_see), max(0, self.y - self.sight_see) x1, y1 = min(self.board.width, self.x + self.sight_see + 1), min(self.board.height, self.y + self.sight_see + 1) grid = Grid(matrix=self.get_matrix(x0, y0, x1, y1)) x_goal, y_goal = self.compute_sight_see_goal(x0, y0, x1, y1) start = grid.node(self.x - x0, self.y - y0) end = grid.node(x_goal, y_goal) if self.use_diagonal: finder = AStarFinder(diagonal_movement=DiagonalMovement.always) else: finder = AStarFinder(diagonal_movement=DiagonalMovement.never) self.path, runs = finder.find_path(start, end, grid) self.path = self.path[1:] for i, step in enumerate(self.path): self.path[i] = (step[0] + x0, step[1] + y0) def reached(self, goal): return goal is not None and self.x == goal[0] and self.y == goal[1] def choose_goal(self): if len(self.knowledge['food']) == 0: return None elif len(self.knowledge['food']) == 1: if self.reached(self.knowledge['food'][0]): return None else: return self.knowledge['food'][0] else: i = random.randrange(len(self.knowledge['food'])) while self.reached(self.knowledge['food'][i]): i = random.randrange(len(self.knowledge['food'])) return self.knowledge['food'][i] def reset(self): self.goal = None self.path = [] self.x = 0 self.y = 0 def move(self): # Scouter has no more goal if self.goal is None or self.goal not in self.knowledge['food']: self.goal = self.choose_goal() self.path = [] # No goal if self.goal is None: return # Scouter has no more path to goal if len(self.path) == 0 or not self.light_compute: self.best_way_to() # No path found, search another goal next time if len(self.path) == 0: self.goal = None return new_pos = self.path[0] self.path = self.path[1:] self.x = new_pos[0] self.y = new_pos[1] # Scouter reached goal if self.reached(self.goal): self.goal = None self.path = []