MapAnalyzer
¶
Submodules¶
Package Contents¶
Classes¶
|
Entry point for the user |
|
Base Class for Representing an “Area” |
|
Higher order “Area” , all of the maps can be summed up by it’s |
|
Base class for all chokes |
|
Wrapper for |
|
VisionBlockerArea are areas containing tiles that hide the units that stand in it, |
-
class
MapAnalyzer.
MapData
(bot: BotAI, loglevel: str = 'ERROR', arcade: bool = False, corner_distance: int = CORNER_MIN_DISTANCE)[source]¶ Entry point for the user
-
property
vision_blockers
(self)¶ Exposing the computed method
vision_blockers
are not to be confused withself.map_vision_blockers
vision_blockers
are the raw data received fromburnysc2
and will be processed later on.
-
get_pyastar_grid
(self, default_weight: float = 1, include_destructables: bool = True)¶ - Return type
Note
To query what is the cost in a certain point, simple do
my_grid[certain_point]
where certain_pointis a
tuple
or asc2.position.Point2
Requests a new pathing grid.
This grid will have all non pathable cells set to
numpy.inf
.pathable cells will be set to the
default_weight
which it’s default is1
.After you get the grid, you can add your own
cost
(also known asweight
orinfluence
)This grid can, and should be reused in the duration of the frame, and should be regenerated(once) on each frame.
Note
destructables that has been destroyed will be updated by default,
the only known use case for
include_destructables
usage is illustrated in the first example belowExample
We want to check if breaking the destructables in our path will make it better,
so we treat destructables as if they were pathable
>>> no_destructables_grid = self.get_pyastar_grid(default_weight = 1, include_destructables= False) >>> # 2 set up a grid with default weight of 300 >>> custom_weight_grid = self.get_pyastar_grid(default_weight = 300)
-
find_lowest_cost_points
(self, from_pos: Point2, radius: float, grid: np.ndarray)¶ - Return type
Union[List[
sc2.position.Point2
], None]
Given an origin point and a radius, will return a list containing the lowest cost points (if there are more than one)
Example
>>> my_grid = self.get_air_vs_ground_grid() >>> position = (100, 80) >>> my_radius = 10 >>> self.find_lowest_cost_points(from_pos=position, radius=my_radius, grid=my_grid) [(90, 80), (91, 76), (91, 77), (91, 78), (91, 79), (91, 80), (91, 81), (92, 74), (92, 75), (92, 76), (92, 77), (92, 78), (92, 79), (92, 80), (92, 81), (93, 73), (93, 74), (93, 75), (93, 76), (93, 77), (93, 78), (93, 79), (93, 80), (93, 81), (94, 72), (94, 73), (94, 74), (94, 75), (94, 76), (94, 77), (95, 73), (95, 74), (95, 75), (95, 76), (96, 74), (96, 75), (97, 74), (97, 75), (98, 74), (98, 75), (99, 74), (99, 75), (100, 74), (100, 75), (101, 74), (101, 75), (102, 74), (102, 75), (103, 74), (103, 75), (104, 74), (104, 75), (105, 74), (105, 75), (106, 74), (106, 75), (107, 74), (107, 75), (108, 74), (108, 75)]
-
lowest_cost_points_array
(self, from_pos: Point2, radius: float, grid: np.ndarray)¶ - Return type
Union[
numpy.ndarray
, None]
Same as find_lowest_cost_points, but returns points in ndarray for use
with numpy/scipy/etc
-
get_climber_grid
(self, default_weight: float = 1, include_destructables: bool = True)¶ - Return type
Climber grid is a grid modified by the c extension, and is used for units that can climb,
such as Reaper, Colossus
This grid can be reused in the duration of the frame,
and should be regenerated(once) on each frame.
This grid also gets updated with all nonpathables when requested
such as structures, and destructables
Example
>>> updated_climber_grid = self.get_climber_grid(default_weight = 1)
-
get_air_vs_ground_grid
(self, default_weight: float = 100)¶ - Return type
air_vs_ground
grid is computed in a way that lowers the cost of nonpathable terrain,making air units naturally “drawn” to it.
Caution
Requesting a grid with a
default_weight
of 1 is pointless,and will result in a
MapData.get_clean_air_grid()
Example
>>> air_vs_ground_grid = self.get_air_vs_ground_grid()
-
get_clean_air_grid
(self, default_weight: float = 1)¶ - Return type
Will return a grid marking every cell as pathable with
default_weight
See also
-
pathfind_pyastar
(self, start: Union[Tuple[float, float], Point2], goal: Union[Tuple[float, float], Point2], grid: Optional[ndarray] = None, allow_diagonal: bool = False, sensitivity: int = 1)¶ - Return type
Union[List[
sc2.position.Point2
], None]
Will return the path with lowest cost (sum) given a weighted array (
grid
),start
, andgoal
.IF NO
grid
has been provided, will request a fresh grid fromPather
If no path is possible, will return
None
Tip
sensitivity
indicates how to slice the path, just like doing:result_path = path[::sensitivity]
where
path
is the return value from this functionthis is useful since in most use cases you wouldn’t want to get each and every single point,
getting every n-
th
point works better in practiceCaution
allow_diagonal=True
will result in a slight performance penalty.However, if you don’t over-use it, it will naturally generate shorter paths,
by converting(for example)
move_right + move_up
intomove_top_right
etc.Example
>>> my_grid = self.get_pyastar_grid() >>> # start / goal could be any tuple / Point2 >>> st, gl = (50,75) , (100,100) >>> path = self.pathfind_pyastar(start=st,goal=gl,grid=my_grid,allow_diagonal=True, sensitivity=3)
-
pathfind
(self, start: Union[Tuple[float, float], Point2], goal: Union[Tuple[float, float], Point2], grid: Optional[ndarray] = None, large: bool = False, smoothing: bool = False, sensitivity: int = 1)¶ - Return type
Union[List[
sc2.position.Point2
], None]
Will return the path with lowest cost (sum) given a weighted array (
grid
),start
, andgoal
.IF NO
grid
has been provided, will request a fresh grid fromPather
If no path is possible, will return
None
sensitivity
indicates how to slice the path, just like doing:result_path = path[::sensitivity]
where
path
is the return value from this functionthis is useful since in most use cases you wouldn’t want to get each and every single point,
getting every n-
th
point works better in practice`` large`` is a boolean that determines whether we are doing pathing with large unit sizes like Thor and Ultralisk. When it’s false the pathfinding is using unit size 1, so if you want to a guarantee that a unit with size > 1 fits through the path then large should be True.
smoothing
tries to do a similar thing on the c side but to the maximum extent possible. it will skip all the waypoints it can if taking the straight line forward is better according to the influence gridExample
>>> my_grid = self.get_pyastar_grid() >>> # start / goal could be any tuple / Point2 >>> st, gl = (50,75) , (100,100) >>> path = self.pathfind(start=st,goal=gl,grid=my_grid, large=False, smoothing=False, sensitivity=3)
-
add_cost
(self, position: Tuple[float, float], radius: float, grid: ndarray, weight: float = 100, safe: bool = True, initial_default_weights: float = 0)¶ - Return type
Will add cost to a circle-shaped area with a center
position
and radiusradius
weight of 100
Warning
When
safe=False
the Pather will not adjust illegal values below 1 which could result in a crash`
-
save
(self, filename)¶ Save Plot to a file, much like
plt.save(filename)
-
show
(self)¶ Calling debugger to show, just like
plt.show()
but in case there will be changes in debugger,This method will always be compatible
-
close
(self)¶ Close an opened plot, just like
plt.close()
but in case there will be changes in debugger,This method will always be compatible
-
static
indices_to_points
(indices: Union[ndarray, Tuple[ndarray, ndarray]])¶ - Return type
set
(Union[tuple
(int
,int
),sc2.position.Point2
)
Convert indices to a set of points(
tuples
, notPoint2
)Will only work when both dimensions are of same length
-
static
points_to_indices
(points: Set[Tuple[float, float]])¶ - Return type
Tuple[numpy.ndarray, numpy.ndarray]
Convert a set / list of points to a tuple of two 1d numpy arrays
-
points_to_numpy_array
(self, points: Union[Set[Tuple[int64, int64]], List[Point2], Set[Point2]], default_value: int = 1)¶ - Return type
Convert points to numpy ndarray
Caution
Will handle safely(by ignoring) points that are
out of bounds
, without warning
-
static
distance
(p1: Point2, p2: Point2)¶ - Return type
float64
Euclidean distance
-
static
distance_squared
(p1: Point2, p2: Point2)¶ - Return type
float64
Euclidean distance squared
-
static
closest_node_idx
(node: Union[Point2, ndarray], nodes: Union[List[Tuple[int, int]], ndarray])¶ - Return type
Given a list of
nodes
and a singlenode
,will return the index of the closest node in the list to
node
-
closest_towards_point
(self, points: List[Point2], target: Union[Point2, tuple])¶ - Return type
Given a list/set of points, and a target,
will return the point that is closest to that target
Example
Calculate a position for tanks in direction to the enemy forces passing in the Area’s corners as points and enemy army’s location as target
>>> enemy_army_position = (50,50) >>> my_base_location = self.bot.townhalls[0].position >>> my_region = self.where_all(my_base_location)[0] >>> best_siege_spot = self.closest_towards_point(points=my_region.corner_points, target=enemy_army_position) >>> best_siege_spot (49, 52)
-
region_connectivity_all_paths
(self, start_region: Region, goal_region: Region, not_through: Optional[List[Region]] = None)¶ - Parameters
start_region –
Region
goal_region –
Region
not_through – Optional[List[
Region
]]
- Return type
List[List[
Region
]]
Returns all possible paths through all
Region
(via ramps),can exclude a region by passing it in a not_through list
-
where_all
(self, point: Union[Point2, tuple])¶ - Return type
List[Union[
Region
,ChokeArea
,VisionBlockerArea
,MDRamp
]]
Will return a list containing all
Polygon
that occupy the given point.If a
Region
exists in that list, it will be the first itemExample
>>> # query in which region is the enemy main >>> position = self.bot.enemy_start_locations[0].position >>> all_polygon_areas_in_position = self.where_all(position) >>> all_polygon_areas_in_position [Region 4]
>>> enemy_main_base_region = all_polygon_areas_in_position[0] >>> enemy_main_base_region Region 4
>>> # now it is very easy to know which region is the enemy's natural >>> # connected_regions is a property of a Region >>> enemy_natural_region = enemy_main_base_region.connected_regions[0] >>> # will return Region 1 or 6 for goldenwall depending on starting position
-
where
(self, point: Union[Point2, tuple])¶ - Return type
Union[
Region
,ChokeArea
,VisionBlockerArea
,MDRamp
]
Will query a point on the map and will return the first result in the following order:
-
in_region_p
(self, point: Union[Point2, tuple])¶ - Return type
Optional[
Region
]
Will query if a point is in, and in which Region using Set of Points <fast>
-
draw_influence_in_game
(self, grid: ndarray, lower_threshold: int = 1, upper_threshold: int = 1000, color: Tuple[int, int, int] = 201, 168, 79, size: int = 13)¶ - Return type
Draws influence (cost) values of a grid in game.
Caution
Setting the lower threshold too low impacts performance since almost every value will get drawn.
It’s recommended that this is set to the relevant grid’s default weight value.
Example
>>> self.ground_grid = self.get_pyastar_grid(default_weight=1) >>> self.ground_grid = self.add_cost((100, 100), radius=15, grid=self.ground_grid, weight=50) >>> # self.draw_influence_in_game(self.ground_grid, lower_threshold=1) # commented out for doctest
-
plot_map
(self, fontdict: dict = None, save: Optional[bool] = None, figsize: int = 20)¶ Plot map (does not
show
orsave
)
-
plot_influenced_path_pyastar
(self, start: Union[Tuple[float, float], Point2], goal: Union[Tuple[float, float], Point2], weight_array: ndarray, allow_diagonal=False, name: Optional[str] = None, fontdict: dict = None)¶ A useful debug utility method for experimenting with the
Pather
module
-
plot_influenced_path
(self, start: Union[Tuple[float, float], Point2], goal: Union[Tuple[float, float], Point2], weight_array: ndarray, large: bool = False, smoothing: bool = False, name: Optional[str] = None, fontdict: dict = None)¶ A useful debug utility method for experimenting with the
Pather
module
-
property
-
class
MapAnalyzer.
Polygon
(map_data: MapData, array: ndarray)[source]¶ Base Class for Representing an “Area”
-
property
buildables
(self)¶ - Return type
BuildablePoints
Is a responsible for holding and updating the buildable points of it’s respected
Polygon
-
property
regions
(self)¶ - Return type
List[
Region
]
Filters out every Polygon that is not a region, and is inside / bordering with
self
-
property
nodes
(self)¶ List of
Point2
-
property
corner_array
(self)¶ - Return type
ndarray
-
property
width
(self)¶ Lazy width calculation, will be approx 0.5 < x < 1.5 of real width
-
property
corner_points
(self)¶ - Return type
List[
Point2
]
-
property
center
(self)¶ Since the center is always going to be a
float
,and for performance considerations we use integer coordinates.
We will return the closest point registered
-
property
perimeter
(self)¶ The perimeter is interpolated between inner and outer cell-types using broadcasting
-
property
perimeter_points
(self)¶ Useful method for getting perimeter points
-
property
area
(self)¶ Sum of all points
-
property
-
class
MapAnalyzer.
Region
(map_data: MapData, array: np.ndarray, label: int, map_expansions: List[Point2])[source]¶ Bases:
MapAnalyzer.Polygon.Polygon
Higher order “Area” , all of the maps can be summed up by it’s
Region
Tip
A
Region
may contain otherPolygon
inside it,But it will never share a point with another
Region
-
property
base_locations
(self)¶ base_locations inside
self
-
property
-
class
MapAnalyzer.
ChokeArea
(array: np.ndarray, map_data: MapData)[source]¶ Bases:
MapAnalyzer.Polygon.Polygon
Base class for all chokes
-
class
MapAnalyzer.
MDRamp
(map_data: MapData, array: np.ndarray, ramp: sc2Ramp)[source]¶ Bases:
MapAnalyzer.constructs.ChokeArea
Wrapper for
sc2.game_info.Ramp
,is responsible for calculating the relevant
Region
-
closest_region
(self, region_list)¶ Will return the closest region with respect to self
-
-
class
MapAnalyzer.
VisionBlockerArea
(map_data: MapData, array: np.ndarray)[source]¶ Bases:
MapAnalyzer.constructs.ChokeArea
VisionBlockerArea are areas containing tiles that hide the units that stand in it,
(for example, bushes)
Units that attack from within a
VisionBlockerArea
cannot be targeted by units that do not stand inside
Indices and tables