def _djikstra(board, my_position, bombs, enemies, depth=None): def out_of_range(p1, p2): x1, y1 = p1 x2, y2 = p2 return depth is not None and abs(y2 - y1) + abs(x2 - x1) > depth items = defaultdict(list) dist = {} prev = {} Q = [] for r in range(len(board)): for c in range(len(board[0])): position = (r, c) if not utility.position_is_fog(board, position): dist[position] = np.inf prev[position] = None Q.append(position) dist[my_position] = 0 for bomb in bombs: if bomb['position'] == my_position: items[utility.Item.Bomb].append(my_position) while Q: Q = sorted(Q, key=lambda position: dist[position]) position = Q.pop(0) if utility.position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if not utility.position_on_board( board, new_position) or utility.position_is_fog( board, new_position): continue if out_of_range(my_position, new_position): continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position item = utility.Item(board[position]) items[item].append(position) return items, dist, prev
def _djikstra(board, my_position, bombs, enemies): items = defaultdict(list) dist = {} prev = {} Q = [] for r in range(len(board)): for c in range(len(board[0])): position = (r, c) if board[position] != utility.Item.Fog.value: dist[position] = inf prev[position] = None Q.append(position) dist[my_position] = 0 for bomb in bombs: if bomb['position'] == my_position: items[utility.Item.Bomb].append(my_position) while Q: Q = sorted(Q, key=lambda position: dist[position]) position = Q.pop(0) if utility.position_is_passable(board, position, enemies): x, y = position val = dist[(x, y)] + 1 for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_position = (row + x, col + y) if not utility.position_on_board( board, new_position) or utility.position_is_fog( board, new_position): continue if val < dist[new_position]: dist[new_position] = val prev[new_position] = position item = utility.Item(board[position]) items[item].append(position) return items, dist, prev
def _find_safe_directions(self, board, my_position, unsafe_directions, bombs, enemies): # All directions are unsafe. Return a position that won't leave us locked. safe = [] if len(unsafe_directions) == 4: next_board = board.copy() next_board[my_position] = utility.Item.Bomb.value for direction, bomb_range in unsafe_directions.items(): next_position = utility.get_next_position( my_position, direction) nx, ny = next_position if not utility.position_on_board(next_board, next_position) or \ not utility.position_is_passable(next_board, next_position, enemies): continue is_stuck = True next_items, next_dist, next_prev = self._djikstra( next_board, next_position, bombs, enemies, depth=10) for passage_position in next_items.get(utility.Item.Passage): position_dist = next_dist[passage_position] if position_dist == np.inf: continue if position_dist > bomb_range: is_stuck = False break px, py = passage_position if nx != px and ny != py: is_stuck = False break if not is_stuck: safe.append(direction) if not safe: safe = [utility.Action.Stop] return safe x, y = my_position disallowed = [] # The directions that will go off the board. for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]: position = (x + row, y + col) direction = utility.get_direction(my_position, position) # Don't include any direction that will go off of the board. if not utility.position_on_board(board, position): disallowed.append(direction) continue # Don't include any direction that we know is unsafe. if direction in unsafe_directions: continue if utility.position_is_passable( board, position, enemies) or utility.position_is_fog( board, position): safe.append(direction) if not safe: # We don't have any safe directions, so return something that is allowed. safe = [k for k in unsafe_directions if k not in disallowed] if not safe: # We don't have ANY directions. So return the stop choice. return [utility.Action.Stop] return safe