def _set_default_grids(self): # need to consider the placement arr because our base minerals, geysers and townhall # are not pathable in the pathing grid # we manage those manually so they are accurate through the game self.default_grid = np.fmax(self.map_data.path_arr, self.map_data.placement_arr).T # Fixing platforms on Submarine which reapers can climb onto not being pathable # Don't use the entire name because we also use the modified maps # with different names if "Submarine" in self.map_data.map_name: self.default_grid[116, 43] = 1 self.default_grid[51, 120] = 1 self.default_grid_nodestr = self.default_grid.copy() self.destructables_included = {} self.minerals_included = {} # set rocks and mineral walls to pathable in the beginning # these will be set nonpathable when updating grids for the destructables # that still exist for dest in self.map_data.bot.destructables: self.destructables_included[dest.position] = dest if "unbuildable" not in dest.name.lower( ) and "acceleration" not in dest.name.lower(): change_destructable_status_in_grid(self.default_grid, dest, 0) change_destructable_status_in_grid(self.default_grid_nodestr, dest, 1) # set each geyser as non pathable, these don't update during the game for geyser in self.map_data.bot.vespene_geyser: left_bottom = geyser.position.offset((-1.5, -1.5)) x_start = int(left_bottom[0]) y_start = int(left_bottom[1]) x_end = int(x_start + 3) y_end = int(y_start + 3) self.default_grid[x_start:x_end, y_start:y_end] = 0 self.default_grid_nodestr[x_start:x_end, y_start:y_end] = 0 for mineral in self.map_data.bot.mineral_field: self.minerals_included[mineral.position] = mineral x1 = int(mineral.position[0]) x2 = x1 - 1 y = int(mineral.position[1]) self.default_grid[x1, y] = 0 self.default_grid[x2, y] = 0 self.default_grid_nodestr[x1, y] = 0 self.default_grid_nodestr[x2, y] = 0
def _add_non_pathables_ground( self, grid: ndarray, include_destructables: bool = True) -> ndarray: ret_grid = grid.copy() nonpathables = self.map_data.bot.structures.not_flying nonpathables.extend(self.map_data.bot.enemy_structures.not_flying) nonpathables = nonpathables.filter( lambda x: (x.type_id != UnitID.SUPPLYDEPOTLOWERED or x.is_active) and (x.type_id != UnitID.CREEPTUMOR or not x.is_ready)) for obj in nonpathables: size = 1 if obj.type_id in buildings_2x2: size = 2 elif obj.type_id in buildings_3x3: size = 3 elif obj.type_id in buildings_5x5: size = 5 left_bottom = obj.position.offset((-size / 2, -size / 2)) x_start = int(left_bottom[0]) y_start = int(left_bottom[1]) x_end = int(x_start + size) y_end = int(y_start + size) ret_grid[x_start:x_end, y_start:y_end] = 0 # townhall sized buildings should have their corner spots pathable if size == 5: ret_grid[x_start, y_start] = 1 ret_grid[x_start, y_end - 1] = 1 ret_grid[x_end - 1, y_start] = 1 ret_grid[x_end - 1, y_end - 1] = 1 if len(self.minerals_included ) != self.map_data.bot.mineral_field.amount: new_positions = set(m.position for m in self.map_data.bot.mineral_field) old_mf_positions = set(self.minerals_included) missing_positions = old_mf_positions - new_positions for mf_position in missing_positions: x1 = int(mf_position[0]) x2 = x1 - 1 y = int(mf_position[1]) ret_grid[x1, y] = 1 ret_grid[x2, y] = 1 self.default_grid[x1, y] = 1 self.default_grid[x2, y] = 1 self.default_grid_nodestr[x1, y] = 1 self.default_grid_nodestr[x2, y] = 1 del self.minerals_included[mf_position] if (include_destructables and len(self.destructables_included) != self.map_data.bot.destructables.amount): new_positions = set(d.position for d in self.map_data.bot.destructables) old_dest_positions = set(self.destructables_included) missing_positions = old_dest_positions - new_positions for dest_position in missing_positions: dest = self.destructables_included[dest_position] change_destructable_status_in_grid(ret_grid, dest, 1) change_destructable_status_in_grid(self.default_grid, dest, 1) del self.destructables_included[dest_position] return ret_grid