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 SensingScouter(DumbScouter): def __init__(self, board, knowledge, x, y, use_diagonal=False, sightline=-1, light_compute=True): DumbScouter.__init__(self, board, knowledge, x, y) self.use_diagonal = use_diagonal self.sight_see = sightline if sightline > 0 else 1 self.light_compute = light_compute 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)) * 1.5 elif self.board.is_touched(x0 + x, y0 + y): matrix[x, y] = Board.MAX_BLOB * 2 else: matrix[x, y] = 1 return np.transpose(matrix) def choose_goal(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) mask = np.zeros((x1 - x0, y1 - y0), dtype=bool) mask[self.x - x0, self.y - y0] = True see = np.ma.masked_where(mask, self.board.dropped_blob[x0:x1, y0:y1]) min_indices = np.ma.where(see == np.min(see)) if len(min_indices[0]) == 0: return None else: i = np.random.randint(len(min_indices[0])) return min_indices[0][i] + x0, min_indices[1][i] + y0 def best_way_to(self): if self.sight_see > 0: 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) else: x0, y0 = 0, 0 x1, y1 = self.board.width, self.board.height grid = Grid(matrix=self.get_matrix(x0, y0, x1, y1)) start = grid.node(self.x - x0, self.y - y0) end = grid.node(self.goal[0] - x0, self.goal[1] - y0) 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 move(self): # Scouter has no more goal if self.goal is None: # or self.board.get_blob(self.goal[0], self.goal[1]) != 0: self.goal = self.choose_goal() if self.goal[0] == self.x and self.goal[1] == self.y: print("Shouldn't happen") 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 = [] def reset(self): self.goal = None self.path = [] self.x = 0 self.y = 0