Source code for MapAnalyzer.cext.wrapper

import numpy as np

try:
    from .mapanalyzerext import astar as ext_astar, get_map_data as ext_get_map_data
except ImportError:
    from mapanalyzerext import astar as ext_astar, get_map_data as ext_get_map_data

from typing import Optional, Tuple, Union, List, Set
from sc2.position import Point2, Rect


[docs]class CMapChoke: """ CMapChoke holds the choke data coming from c extension main_line pair of floats representing the middle points of the sides of the choke lines all the lines from side to side side1 points on side1 side2 points on side2 pixels all the points inside the choke area, should include the sides and the points inside min_length minimum distance between the sides of the choke id an integer to represent the choke """ main_line: Tuple[Tuple[float, float], Tuple[float, float]] lines: List[Tuple[Tuple[int, int], Tuple[int, int]]] side1: List[Tuple[int, int]] side2: List[Tuple[int, int]] pixels: Set[Tuple[int, int]] min_length: float id: int def __init__(self, choke_id, main_line, lines, side1, side2, pixels, min_length): self.id = choke_id self.main_line = main_line self.lines = lines self.side1 = side1 self.side2 = side2 self.pixels = set(pixels) self.min_length = min_length def __repr__(self) -> str: return f"[{self.id}]CMapChoke; {len(self.pixels)}"
def astar_path( weights: np.ndarray, start: Tuple[int, int], goal: Tuple[int, int], large: bool = False, smoothing: bool = False) -> Union[np.ndarray, None]: # For the heuristic to be valid, each move must have a positive cost. # Demand costs above 1 so floating point inaccuracies aren't a problem # when comparing costs if weights.min(axis=None) < 1: raise ValueError("Minimum cost to move must be above or equal to 1, but got %f" % ( weights.min(axis=None))) # Ensure start is within bounds. if (start[0] < 0 or start[0] >= weights.shape[0] or start[1] < 0 or start[1] >= weights.shape[1]): raise ValueError(f"Start of {start} lies outside grid.") # Ensure goal is within bounds. if (goal[0] < 0 or goal[0] >= weights.shape[0] or goal[1] < 0 or goal[1] >= weights.shape[1]): raise ValueError(f"Goal of {goal} lies outside grid.") height, width = weights.shape start_idx = np.ravel_multi_index(start, (height, width)) goal_idx = np.ravel_multi_index(goal, (height, width)) path = ext_astar( weights.flatten(), height, width, start_idx, goal_idx, large, smoothing ) return path class CMapInfo: climber_grid: np.ndarray overlord_spots: Optional[List[Point2]] chokes: List[CMapChoke] def __init__(self, walkable_grid: np.ndarray, height_map: np.ndarray, playable_area: Rect): """ walkable_grid and height_map are matrices of type uint8 """ # grids are transposed and the c extension atm calls the y axis the x axis and vice versa # so switch the playable area limits around c_start_y = int(playable_area.x) c_end_y = int(playable_area.x + playable_area.width) c_start_x = int(playable_area.y) c_end_x = int(playable_area.y + playable_area.height) self.climber_grid, overlord_data, choke_data = self._get_map_data(walkable_grid, height_map, c_start_y, c_end_y, c_start_x, c_end_x) self.overlord_spots = list(map(Point2, overlord_data)) self.chokes = [] id_counter = 0 for c in choke_data: self.chokes.append(CMapChoke(id_counter, c[0], c[1], c[2], c[3], c[4], c[5])) id_counter += 1 @staticmethod def _get_map_data(walkable_grid: np.ndarray, height_map: np.ndarray, start_y: int, end_y: int, start_x: int, end_x: int): height, width = walkable_grid.shape return ext_get_map_data(walkable_grid.flatten(), height_map.flatten(), height, width, start_y, end_y, start_x, end_x)