From ac5fc1ab15a72bdede72af972faaa0b4cd1cef2a Mon Sep 17 00:00:00 2001 From: manantt Date: Sun, 5 May 2019 16:01:55 +0200 Subject: [PATCH 1/5] Added minimap file --- sc2/minimap.py | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 sc2/minimap.py diff --git a/sc2/minimap.py b/sc2/minimap.py new file mode 100644 index 000000000..943ea8a98 --- /dev/null +++ b/sc2/minimap.py @@ -0,0 +1,119 @@ +from sc2.cache import property_cache_forever, property_cache_once_per_frame +from sc2.constants import PYLON + +import random +import cv2 +import numpy as np + +import datetime + +class Minimap: + def __init__( + self, + game, + map_scale=3, + show_heighmap=True, + show_ramps=True, + show_creep=True, + show_psi=True, + show_minerals=True, + show_geysers=True, + show_allies=True, + show_enemies=True + ): + self.game = game + self.map_scale = map_scale + self.show_heighmap = show_heighmap + self.show_ramps = show_ramps + self.show_creep = show_creep + self.show_psi = show_psi + self.show_minerals = show_psi + self.show_geysers = show_psi + self.show_allies = show_psi + self.show_enemies = show_psi + + @property_cache_forever + def empty_map(self): + map_scale = self.map_scale + map_data = np.zeros((self.game.game_info.map_size[1]*map_scale, self.game.game_info.map_size[0]*map_scale, 3), np.uint8) + return map_data + + @property_cache_forever + def heighmap(self): + # gets the min and max heigh of the map for a better contrast + h_min = np.amin(self.game._game_info.terrain_height.data_numpy) + h_max = np.amax(self.game._game_info.terrain_height.data_numpy) + multiplier = 150 / (h_max - h_min) + map_data = self.empty_map + for (y,x), h in np.ndenumerate(self.game._game_info.terrain_height.data_numpy): + color = (h - h_min) * multiplier + cv2.rectangle(map_data, (x*self.map_scale, y*self.map_scale), (x*self.map_scale+self.map_scale, y*self.map_scale+self.map_scale), (color, color, color), -1) + return map_data + + def add_psi(self, map_data): + psi = map_data.copy() + + for psi_provider in self.game.units(PYLON): + psi_center = psi_provider.position + psi_radius = 6.5 + cv2.circle(map_data, (int(psi_center[0]*self.map_scale), int(psi_center[1]*self.map_scale)), int(psi_radius*self.map_scale), (255, 255, 86), -1) + + alpha = 0.3 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, psi, 1 - alpha, 0) + + def add_ramps(self, map_data): + for r in self.game.game_info.map_ramps: + for p in r.points: + cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 2, (120, 100, 100), -1) + for p in r.upper: + cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 1, (160, 140, 140), -1) + for p in r.lower: + cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 1, (100, 80, 80), -1) + return map_data + + def add_minerals(self, map_data): + for mineral in self.game.state.resources: + mine_pos = mineral.position + cv2.circle(map_data, (int(mine_pos[0]*self.map_scale), int(mine_pos[1]*self.map_scale)), int(mineral.radius*self.map_scale), (255, 255, 86), -1) + return map_data + + def add_geysers(self, map_data): + for g in self.game.state.vespene_geyser: + g_pos = g.position + cv2.circle(map_data, (int(g_pos[0]*self.map_scale), int(g_pos[1]*self.map_scale)), int(g.radius*self.map_scale), (0, 127, 63), -1) + + def draw_map(self): + if self.show_heighmap: + map_data = np.copy(self.heighmap) + else: + map_data = np.copy(self.empty_map) + if self.show_psi: + map_data = self.add_psi(map_data) + if self.show_ramps: + self.add_ramps(map_data) + if self.show_minerals: + self.add_minerals(map_data) + if self.show_geysers: + self.add_geysers(map_data) + + # neutral units self.observation.raw_data.units + #for unit in self.game.state.towers: + # cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 250, 250), -1) + for unit in self.game.state.destructables: + cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (80, 100, 120), -1) + # ally units + for unit in self.game.units: + if unit.is_structure: + cv2.rectangle(map_data, (int(unit.position[0]*self.map_scale)-self.map_scale, int(unit.position[1]*self.map_scale)-self.map_scale), (int(unit.position[0]*self.map_scale+unit.radius*self.map_scale), int(unit.position[1]*self.map_scale+unit.radius*self.map_scale)), (0, 255, 0), -1) + else: + cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 255, 0), -1) + for unit in self.game.known_enemy_units: + if unit.is_structure: + cv2.rectangle(map_data, (int(unit.position[0]*self.map_scale)-self.map_scale, int(unit.position[1]*self.map_scale)-self.map_scale), (int(unit.position[0]*self.map_scale+unit.radius*self.map_scale), int(unit.position[1]*self.map_scale+unit.radius*self.map_scale)), (0, 0, 255), -1) + else: + cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 0, 255), -1) + flipped = cv2.flip(map_data, 0) + resized = flipped#cv2.resize(flipped, dsize=None, fx=2, fy=2) + cv2.imshow('Intel', resized) + cv2.waitKey(1) \ No newline at end of file From 91ec581239f54296201c2549ef16974777d6f962 Mon Sep 17 00:00:00 2001 From: manantt Date: Sun, 5 May 2019 17:45:25 +0200 Subject: [PATCH 2/5] Refactored minimap, some fixes --- sc2/minimap.py | 411 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 302 insertions(+), 109 deletions(-) diff --git a/sc2/minimap.py b/sc2/minimap.py index 943ea8a98..d454f5b2e 100644 --- a/sc2/minimap.py +++ b/sc2/minimap.py @@ -7,113 +7,306 @@ import datetime + class Minimap: - def __init__( - self, - game, - map_scale=3, - show_heighmap=True, - show_ramps=True, - show_creep=True, - show_psi=True, - show_minerals=True, - show_geysers=True, - show_allies=True, - show_enemies=True - ): - self.game = game - self.map_scale = map_scale - self.show_heighmap = show_heighmap - self.show_ramps = show_ramps - self.show_creep = show_creep - self.show_psi = show_psi - self.show_minerals = show_psi - self.show_geysers = show_psi - self.show_allies = show_psi - self.show_enemies = show_psi - - @property_cache_forever - def empty_map(self): - map_scale = self.map_scale - map_data = np.zeros((self.game.game_info.map_size[1]*map_scale, self.game.game_info.map_size[0]*map_scale, 3), np.uint8) - return map_data - - @property_cache_forever - def heighmap(self): - # gets the min and max heigh of the map for a better contrast - h_min = np.amin(self.game._game_info.terrain_height.data_numpy) - h_max = np.amax(self.game._game_info.terrain_height.data_numpy) - multiplier = 150 / (h_max - h_min) - map_data = self.empty_map - for (y,x), h in np.ndenumerate(self.game._game_info.terrain_height.data_numpy): - color = (h - h_min) * multiplier - cv2.rectangle(map_data, (x*self.map_scale, y*self.map_scale), (x*self.map_scale+self.map_scale, y*self.map_scale+self.map_scale), (color, color, color), -1) - return map_data - - def add_psi(self, map_data): - psi = map_data.copy() - - for psi_provider in self.game.units(PYLON): - psi_center = psi_provider.position - psi_radius = 6.5 - cv2.circle(map_data, (int(psi_center[0]*self.map_scale), int(psi_center[1]*self.map_scale)), int(psi_radius*self.map_scale), (255, 255, 86), -1) - - alpha = 0.3 # Transparency factor. - - return cv2.addWeighted(map_data, alpha, psi, 1 - alpha, 0) - - def add_ramps(self, map_data): - for r in self.game.game_info.map_ramps: - for p in r.points: - cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 2, (120, 100, 100), -1) - for p in r.upper: - cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 1, (160, 140, 140), -1) - for p in r.lower: - cv2.circle(map_data, (int(p[0]*self.map_scale), int(p[1]*self.map_scale)), 1, (100, 80, 80), -1) - return map_data - - def add_minerals(self, map_data): - for mineral in self.game.state.resources: - mine_pos = mineral.position - cv2.circle(map_data, (int(mine_pos[0]*self.map_scale), int(mine_pos[1]*self.map_scale)), int(mineral.radius*self.map_scale), (255, 255, 86), -1) - return map_data - - def add_geysers(self, map_data): - for g in self.game.state.vespene_geyser: - g_pos = g.position - cv2.circle(map_data, (int(g_pos[0]*self.map_scale), int(g_pos[1]*self.map_scale)), int(g.radius*self.map_scale), (0, 127, 63), -1) - - def draw_map(self): - if self.show_heighmap: - map_data = np.copy(self.heighmap) - else: - map_data = np.copy(self.empty_map) - if self.show_psi: - map_data = self.add_psi(map_data) - if self.show_ramps: - self.add_ramps(map_data) - if self.show_minerals: - self.add_minerals(map_data) - if self.show_geysers: - self.add_geysers(map_data) - - # neutral units self.observation.raw_data.units - #for unit in self.game.state.towers: - # cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 250, 250), -1) - for unit in self.game.state.destructables: - cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (80, 100, 120), -1) - # ally units - for unit in self.game.units: - if unit.is_structure: - cv2.rectangle(map_data, (int(unit.position[0]*self.map_scale)-self.map_scale, int(unit.position[1]*self.map_scale)-self.map_scale), (int(unit.position[0]*self.map_scale+unit.radius*self.map_scale), int(unit.position[1]*self.map_scale+unit.radius*self.map_scale)), (0, 255, 0), -1) - else: - cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 255, 0), -1) - for unit in self.game.known_enemy_units: - if unit.is_structure: - cv2.rectangle(map_data, (int(unit.position[0]*self.map_scale)-self.map_scale, int(unit.position[1]*self.map_scale)-self.map_scale), (int(unit.position[0]*self.map_scale+unit.radius*self.map_scale), int(unit.position[1]*self.map_scale+unit.radius*self.map_scale)), (0, 0, 255), -1) - else: - cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 0, 255), -1) - flipped = cv2.flip(map_data, 0) - resized = flipped#cv2.resize(flipped, dsize=None, fx=2, fy=2) - cv2.imshow('Intel', resized) - cv2.waitKey(1) \ No newline at end of file + def __init__( + self, + game, + map_scale=3, + show_heightmap=True, + show_ramps=True, # note: this need show_heightmap + show_creep=True, + show_psi=True, + show_minerals=True, + show_geysers=True, + show_destructables=True, + show_allies=True, + show_enemies=True, + show_visibility=True, + ): + self.game = game + self.map_scale = map_scale + self.show_heightmap = show_heightmap + self.show_ramps = show_ramps + self.show_creep = show_creep + self.show_psi = show_psi + self.show_minerals = show_minerals + self.show_geysers = show_geysers + self.show_destructables = show_destructables + self.show_allies = show_allies + self.show_enemies = show_enemies + self.show_visibility = show_visibility + + @property_cache_forever + def empty_map(self): + map_scale = self.map_scale + map_data = np.zeros( + ( + self.game.game_info.map_size[1] * map_scale, + self.game.game_info.map_size[0] * map_scale, + 3, + ), + np.uint8, + ) + return map_data + + @property_cache_forever + def heightmap(self): + # gets the min and max heigh of the map for a better contrast + h_min = np.amin(self.game._game_info.terrain_height.data_numpy) + h_max = np.amax(self.game._game_info.terrain_height.data_numpy) + multiplier = 150 / (h_max - h_min) + + map_data = self.empty_map + + for (y, x), h in np.ndenumerate(self.game._game_info.terrain_height.data_numpy): + color = (h - h_min) * multiplier + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + (color, color, color), + -1, + ) + if self.show_ramps: + for r in self.game.game_info.map_ramps: + for p in r.points: + cv2.circle( + map_data, + (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), + 2, + (120, 100, 100), + -1, + ) + for p in r.upper: + cv2.circle( + map_data, + (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), + 1, + (160, 140, 140), + -1, + ) + for p in r.lower: + cv2.circle( + map_data, + (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), + 1, + (100, 80, 80), + -1, + ) + return map_data + + def add_psi(self, map_data): + psi = map_data.copy() + + for psi_provider in self.game.units(PYLON): + psi_center = psi_provider.position + psi_radius = 6.5 + cv2.circle( + map_data, + ( + int(psi_center[0] * self.map_scale), + int(psi_center[1] * self.map_scale), + ), + int(psi_radius * self.map_scale), + (240, 240, 140), + -1, + ) + + alpha = 0.3 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, psi, 1 - alpha, 0) + + def add_minerals(self, map_data): + for mineral in self.game.state.mineral_field: + mine_pos = mineral.position + cv2.rectangle( + map_data, + ( + int((mine_pos[0] - 0.75) * self.map_scale), + int((mine_pos[1] - 0.25) * self.map_scale), + ), + ( + int((mine_pos[0] + 0.75) * self.map_scale), + int((mine_pos[1] + 0.25) * self.map_scale), + ), + (220, 180, 140), + -1, + ) + + def add_geysers(self, map_data): + for g in self.game.state.vespene_geyser: + g_pos = g.position + cv2.rectangle( + map_data, + ( + int((g_pos[0] - g.radius / 2) * self.map_scale), + int((g_pos[1] - g.radius / 2) * self.map_scale), + ), + ( + int((g_pos[0] + g.radius / 2) * self.map_scale), + int((g_pos[1] + g.radius / 2) * self.map_scale), + ), + (130, 220, 170), + -1, + ) + + def add_destructables(self, map_data): + # TODO: make a dictionary that contains all footprints of all destructables to draw them the right way + for unit in self.game.state.destructables: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + (80, 100, 120), + -1, + ) + + def add_allies(self, map_data): + for unit in self.game.units: + if unit.is_structure: + cv2.rectangle( + map_data, + ( + int((unit.position[0] - unit.radius / 2) * self.map_scale), + int((unit.position[1] - unit.radius / 2) * self.map_scale), + ), + ( + int((unit.position[0] + unit.radius / 2) * self.map_scale), + int((unit.position[1] + unit.radius / 2) * self.map_scale), + ), + (0, 255, 0), + -1, + ) + else: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + (0, 255, 0), + -1, + ) + + def add_enemies(self, map_data): + for unit in self.game.known_enemy_units: + if unit.is_structure: + cv2.rectangle( + map_data, + ( + int((unit.position[0] - unit.radius / 2) * self.map_scale), + int((unit.position[1] - unit.radius / 2) * self.map_scale), + ), + ( + int((unit.position[0] + unit.radius / 2) * self.map_scale), + int((unit.position[1] + unit.radius / 2) * self.map_scale), + ), + (0, 0, 255), + -1, + ) + else: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + (0, 0, 255), + -1, + ) + + def add_visibility(self, map_data): + visibility = map_data.copy() + # gets the min and max heigh of the map for a better contrast + v_min = np.amin(self.game.state.visibility.data_numpy) + v_max = np.amax(self.game.state.visibility.data_numpy) + multiplier = 255 / (v_max - v_min) + + for (y, x), v in np.ndenumerate(self.game.state.visibility.data_numpy): + color = (v - v_min) * multiplier + if v != v_min and v != v_max: + print(v_max) + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + (color, color, color), + -1, + ) + + alpha = 0.2 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, visibility, 1 - alpha, 0) + + def draw_map(self): + if self.show_heightmap: + map_data = np.copy(self.heightmap) + else: + map_data = np.copy(self.empty_map) + if self.show_psi: + map_data = self.add_psi(map_data) + if self.show_minerals: + self.add_minerals(map_data) + if self.show_geysers: + self.add_geysers(map_data) + if self.show_destructables: + self.add_destructables(map_data) + if self.show_allies: + self.add_allies(map_data) + if self.show_enemies: + self.add_enemies(map_data) + if self.show_visibility: + map_data = self.add_visibility(map_data) + + # neutral units self.observation.raw_data.units + # for unit in self.game.state.towers: + # cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 250, 250), -1) + + for unit in self.game.known_enemy_units: + if unit.is_structure: + cv2.rectangle( + map_data, + ( + int(unit.position[0] * self.map_scale) - self.map_scale, + int(unit.position[1] * self.map_scale) - self.map_scale, + ), + ( + int( + unit.position[0] * self.map_scale + + unit.radius * self.map_scale + ), + int( + unit.position[1] * self.map_scale + + unit.radius * self.map_scale + ), + ), + (0, 0, 255), + -1, + ) + else: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + (0, 0, 255), + -1, + ) + flipped = cv2.flip(map_data, 0) + resized = flipped # cv2.resize(flipped, dsize=None, fx=2, fy=2) + cv2.imshow("Intel", resized) + cv2.waitKey(1) From 36c43a498e73c16054c8ddaf5f480d3db3df3908 Mon Sep 17 00:00:00 2001 From: manantt Date: Sun, 5 May 2019 18:38:08 +0200 Subject: [PATCH 3/5] Review fixes --- sc2/minimap.py | 160 +++++++++++++++++++++++++------------------------ 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/sc2/minimap.py b/sc2/minimap.py index d454f5b2e..08619bac5 100644 --- a/sc2/minimap.py +++ b/sc2/minimap.py @@ -14,7 +14,7 @@ def __init__( game, map_scale=3, show_heightmap=True, - show_ramps=True, # note: this need show_heightmap + show_ramps=True, show_creep=True, show_psi=True, show_minerals=True, @@ -22,7 +22,7 @@ def __init__( show_destructables=True, show_allies=True, show_enemies=True, - show_visibility=True, + show_visibility=False, ): self.game = game self.map_scale = map_scale @@ -37,6 +37,18 @@ def __init__( self.show_enemies = show_enemies self.show_visibility = show_visibility + self.colors = { + "ally_units": (0, 255, 0), + "enemy_units": (0, 0, 255), + "psi": (240, 240, 140), + "geysers": (130, 220, 170), + "minerals": (220, 180, 140), + "destructables": (80, 100, 120), + "ramp": (120, 100, 100), + "upperramp": (160, 140, 140), + "lowerramp": (100, 80, 80), + } + @property_cache_forever def empty_map(self): map_scale = self.map_scale @@ -71,34 +83,54 @@ def heightmap(self): (color, color, color), -1, ) - if self.show_ramps: - for r in self.game.game_info.map_ramps: - for p in r.points: - cv2.circle( - map_data, - (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), - 2, - (120, 100, 100), - -1, - ) - for p in r.upper: - cv2.circle( - map_data, - (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), - 1, - (160, 140, 140), - -1, - ) - for p in r.lower: - cv2.circle( - map_data, - (int(p[0] * self.map_scale), int(p[1] * self.map_scale)), - 1, - (100, 80, 80), - -1, - ) return map_data + def add_ramps(self, map_data): + for r in self.game.game_info.map_ramps: + ramp_point_radius = 0.5 + for p in r.points: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["ramp"], + -1, + ) + for p in r.upper: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["upperramp"], + -1, + ) + for p in r.lower: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["lowerramp"], + -1, + ) + def add_psi(self, map_data): psi = map_data.copy() @@ -112,7 +144,7 @@ def add_psi(self, map_data): int(psi_center[1] * self.map_scale), ), int(psi_radius * self.map_scale), - (240, 240, 140), + self.colors["psi"], -1, ) @@ -133,7 +165,7 @@ def add_minerals(self, map_data): int((mine_pos[0] + 0.75) * self.map_scale), int((mine_pos[1] + 0.25) * self.map_scale), ), - (220, 180, 140), + self.colors["minerals"], -1, ) @@ -143,14 +175,14 @@ def add_geysers(self, map_data): cv2.rectangle( map_data, ( - int((g_pos[0] - g.radius / 2) * self.map_scale), - int((g_pos[1] - g.radius / 2) * self.map_scale), + int((g_pos[0] - g.radius) * self.map_scale), + int((g_pos[1] - g.radius) * self.map_scale), ), ( - int((g_pos[0] + g.radius / 2) * self.map_scale), - int((g_pos[1] + g.radius / 2) * self.map_scale), + int((g_pos[0] + g.radius) * self.map_scale), + int((g_pos[1] + g.radius) * self.map_scale), ), - (130, 220, 170), + self.colors["geysers"], -1, ) @@ -164,7 +196,7 @@ def add_destructables(self, map_data): int(unit.position[1] * self.map_scale), ), int(unit.radius * self.map_scale), - (80, 100, 120), + self.colors["destructables"], -1, ) @@ -174,14 +206,14 @@ def add_allies(self, map_data): cv2.rectangle( map_data, ( - int((unit.position[0] - unit.radius / 2) * self.map_scale), - int((unit.position[1] - unit.radius / 2) * self.map_scale), + int((unit.position[0] - unit.radius) * self.map_scale), + int((unit.position[1] - unit.radius) * self.map_scale), ), ( - int((unit.position[0] + unit.radius / 2) * self.map_scale), - int((unit.position[1] + unit.radius / 2) * self.map_scale), + int((unit.position[0] + unit.radius) * self.map_scale), + int((unit.position[1] + unit.radius) * self.map_scale), ), - (0, 255, 0), + self.colors["ally_units"], -1, ) else: @@ -192,7 +224,7 @@ def add_allies(self, map_data): int(unit.position[1] * self.map_scale), ), int(unit.radius * self.map_scale), - (0, 255, 0), + self.colors["ally_units"], -1, ) @@ -202,14 +234,14 @@ def add_enemies(self, map_data): cv2.rectangle( map_data, ( - int((unit.position[0] - unit.radius / 2) * self.map_scale), - int((unit.position[1] - unit.radius / 2) * self.map_scale), + int((unit.position[0] - unit.radius) * self.map_scale), + int((unit.position[1] - unit.radius) * self.map_scale), ), ( - int((unit.position[0] + unit.radius / 2) * self.map_scale), - int((unit.position[1] + unit.radius / 2) * self.map_scale), + int((unit.position[0] + unit.radius) * self.map_scale), + int((unit.position[1] + unit.radius) * self.map_scale), ), - (0, 0, 255), + self.colors["enemy_units"], -1, ) else: @@ -255,6 +287,8 @@ def draw_map(self): map_data = np.copy(self.heightmap) else: map_data = np.copy(self.empty_map) + if self.show_ramps: + self.add_ramps(map_data) if self.show_psi: map_data = self.add_psi(map_data) if self.show_minerals: @@ -274,38 +308,6 @@ def draw_map(self): # for unit in self.game.state.towers: # cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 250, 250), -1) - for unit in self.game.known_enemy_units: - if unit.is_structure: - cv2.rectangle( - map_data, - ( - int(unit.position[0] * self.map_scale) - self.map_scale, - int(unit.position[1] * self.map_scale) - self.map_scale, - ), - ( - int( - unit.position[0] * self.map_scale - + unit.radius * self.map_scale - ), - int( - unit.position[1] * self.map_scale - + unit.radius * self.map_scale - ), - ), - (0, 0, 255), - -1, - ) - else: - cv2.circle( - map_data, - ( - int(unit.position[0] * self.map_scale), - int(unit.position[1] * self.map_scale), - ), - int(unit.radius * self.map_scale), - (0, 0, 255), - -1, - ) flipped = cv2.flip(map_data, 0) resized = flipped # cv2.resize(flipped, dsize=None, fx=2, fy=2) cv2.imshow("Intel", resized) From a5dbfb274f9faf956f1ab3f049304bada39197af Mon Sep 17 00:00:00 2001 From: manantt Date: Sun, 5 May 2019 20:47:33 +0200 Subject: [PATCH 4/5] Added xelnaga towers, creep and blips --- sc2/minimap.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 7 deletions(-) diff --git a/sc2/minimap.py b/sc2/minimap.py index 08619bac5..ed26b3292 100644 --- a/sc2/minimap.py +++ b/sc2/minimap.py @@ -19,9 +19,11 @@ def __init__( show_psi=True, show_minerals=True, show_geysers=True, + show_xelnaga=True, show_destructables=True, show_allies=True, show_enemies=True, + show_blips=True, show_visibility=False, ): self.game = game @@ -32,21 +34,25 @@ def __init__( self.show_psi = show_psi self.show_minerals = show_minerals self.show_geysers = show_geysers + self.show_xelnaga = show_xelnaga self.show_destructables = show_destructables self.show_allies = show_allies self.show_enemies = show_enemies + self.show_blips = show_blips self.show_visibility = show_visibility self.colors = { "ally_units": (0, 255, 0), "enemy_units": (0, 0, 255), "psi": (240, 240, 140), - "geysers": (130, 220, 170), + "creep": (73, 33, 63), + "geysers": (60, 160, 100), "minerals": (220, 180, 140), "destructables": (80, 100, 120), "ramp": (120, 100, 100), "upperramp": (160, 140, 140), "lowerramp": (100, 80, 80), + "xelnaga": (170, 200, 100), } @property_cache_forever @@ -131,6 +137,26 @@ def add_ramps(self, map_data): -1, ) + def add_creep(self, map_data): + creep = map_data.copy() + + for (y, x), v in np.ndenumerate(self.game.state.creep.data_numpy): + if v: + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + self.colors["creep"], + -1, + ) + + alpha = 0.8 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, creep, 1 - alpha, 0) + def add_psi(self, map_data): psi = map_data.copy() @@ -186,6 +212,29 @@ def add_geysers(self, map_data): -1, ) + def add_xelnaga(self, map_data): + for unit in self.game.state.watchtowers: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + self.colors["xelnaga"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(22 * self.map_scale), + self.colors["xelnaga"], + 1, + ) + def add_destructables(self, map_data): # TODO: make a dictionary that contains all footprints of all destructables to draw them the right way for unit in self.game.state.destructables: @@ -256,6 +305,59 @@ def add_enemies(self, map_data): -1, ) + def add_blips(self, map_data): + for unit in self.game.state.blips: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) - 1, + int(unit.position[1] * self.map_scale) - 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) + 1, + int(unit.position[1] * self.map_scale) + 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) + 1, + int(unit.position[1] * self.map_scale) - 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) - 1, + int(unit.position[1] * self.map_scale) + 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + def add_visibility(self, map_data): visibility = map_data.copy() # gets the min and max heigh of the map for a better contrast @@ -265,8 +367,6 @@ def add_visibility(self, map_data): for (y, x), v in np.ndenumerate(self.game.state.visibility.data_numpy): color = (v - v_min) * multiplier - if v != v_min and v != v_max: - print(v_max) cv2.rectangle( map_data, (x * self.map_scale, y * self.map_scale), @@ -289,25 +389,27 @@ def draw_map(self): map_data = np.copy(self.empty_map) if self.show_ramps: self.add_ramps(map_data) + if self.show_psi: + map_data = self.add_creep(map_data) if self.show_psi: map_data = self.add_psi(map_data) if self.show_minerals: self.add_minerals(map_data) if self.show_geysers: self.add_geysers(map_data) + if self.show_xelnaga: + self.add_xelnaga(map_data) if self.show_destructables: self.add_destructables(map_data) if self.show_allies: self.add_allies(map_data) if self.show_enemies: self.add_enemies(map_data) + if self.show_blips: + self.add_blips(map_data) if self.show_visibility: map_data = self.add_visibility(map_data) - # neutral units self.observation.raw_data.units - # for unit in self.game.state.towers: - # cv2.circle(map_data, (int(unit.position[0]*self.map_scale), int(unit.position[1]*self.map_scale)), int(unit.radius*self.map_scale), (0, 250, 250), -1) - flipped = cv2.flip(map_data, 0) resized = flipped # cv2.resize(flipped, dsize=None, fx=2, fy=2) cv2.imshow("Intel", resized) From 74516f59eaf37780f97e982f5f1be31071387a31 Mon Sep 17 00:00:00 2001 From: manantt Date: Tue, 7 May 2019 00:06:33 +0200 Subject: [PATCH 5/5] Added vision blockers and custom points --- minimap.py | 471 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 471 insertions(+) create mode 100644 minimap.py diff --git a/minimap.py b/minimap.py new file mode 100644 index 000000000..4c6ff67f7 --- /dev/null +++ b/minimap.py @@ -0,0 +1,471 @@ +from .cache import property_cache_forever, property_cache_once_per_frame +from .constants import PYLON +from .position import Point2 + +import random +import cv2 +import numpy as np + +import datetime + + +class Minimap: + def __init__( + self, + game, + map_scale=2, + show_heightmap=True, + show_ramps=False, + show_vision_blockers=True, + show_creep=True, + show_psi=True, + show_minerals=True, + show_geysers=True, + show_xelnaga=True, + show_destructables=True, + show_allies=True, + show_enemies=True, + show_blips=True, + show_visibility=False, + custom_points={}, # {Point2([100, 50]): (200, 50, 50),(Point2([101, 120]),Point2([101, 135]),Point2([101, 150])): (200, 250, 250)} + ): + self.game = game + self.map_scale = map_scale + self.show_heightmap = show_heightmap + self.show_ramps = show_ramps + self.show_vision_blockers = show_vision_blockers + self.show_creep = show_creep + self.show_psi = show_psi + self.show_minerals = show_minerals + self.show_geysers = show_geysers + self.show_xelnaga = show_xelnaga + self.show_destructables = show_destructables + self.show_allies = show_allies + self.show_enemies = show_enemies + self.show_blips = show_blips + self.show_visibility = show_visibility + self.custom_points = custom_points + + self.colors = { + "ally_units": (0, 255, 0), + "enemy_units": (0, 0, 255), + "psi": (240, 240, 140), + "creep": (73, 33, 63), + "geysers": (60, 160, 100), + "minerals": (220, 180, 140), + "destructables": (80, 100, 120), + "vision_blockers": (0, 0, 0), + "ramp": (110, 100, 100), + "upperramp": (120, 110, 110), + "lowerramp": (100, 90, 90), + "xelnaga": (170, 200, 100), + } + + def draw_map(self): + if self.show_heightmap: + map_data = np.copy(self.heightmap) + else: + map_data = np.copy(self.empty_map) + if self.show_ramps: + self.add_ramps(map_data) + if self.show_vision_blockers: + map_data = self.add_vision_blockers(map_data) + if self.show_psi: + map_data = self.add_creep(map_data) + if self.show_psi: + map_data = self.add_psi(map_data) + if self.show_minerals: + self.add_minerals(map_data) + if self.show_geysers: + self.add_geysers(map_data) + if self.show_xelnaga: + self.add_xelnaga(map_data) + if self.show_destructables: + self.add_destructables(map_data) + if self.show_allies: + self.add_allies(map_data) + if self.show_enemies: + self.add_enemies(map_data) + if self.show_blips: + self.add_blips(map_data) + if self.show_blips: + self.add_blips(map_data) + self.add_custom_points(map_data) + + flipped = cv2.flip(map_data, 0) + cv2.imshow("Debug minimap", flipped) + cv2.waitKey(1) + + @property_cache_forever + def empty_map(self): + map_scale = self.map_scale + map_data = np.zeros( + ( + self.game.game_info.map_size[1] * map_scale, + self.game.game_info.map_size[0] * map_scale, + 3, + ), + np.uint8, + ) + return map_data + + @property_cache_forever + def heightmap(self): + # gets the min and max heigh of the map for a better contrast + h_min = np.amin(self.game._game_info.terrain_height.data_numpy) + h_max = np.amax(self.game._game_info.terrain_height.data_numpy) + multiplier = 160 / (h_max - h_min) + + map_data = self.empty_map + + for (y, x), h in np.ndenumerate(self.game._game_info.terrain_height.data_numpy): + color = (h - h_min) * multiplier + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + (color * 18 / 20, color * 19 / 20, color), + -1, + ) + return map_data + + def add_ramps(self, map_data): + for r in self.game.game_info.map_ramps: + ramp_point_radius = 0.5 + for p in r.points: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["ramp"], + -1, + ) + for p in r.upper: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["upperramp"], + -1, + ) + for p in r.lower: + cv2.rectangle( + map_data, + ( + (int(p[0] - ramp_point_radius) * self.map_scale), + int((p[1] - ramp_point_radius) * self.map_scale), + ), + ( + (int(p[0] + ramp_point_radius) * self.map_scale), + int((p[1] + ramp_point_radius) * self.map_scale), + ), + self.colors["lowerramp"], + -1, + ) + + def add_vision_blockers(self, map_data): + vb = map_data.copy() + for p in self.game.game_info.vision_blockers: + vision_blocker_point_radius = 0.5 + cv2.rectangle( + vb, + ( + (int(p[0] - vision_blocker_point_radius) * self.map_scale), + int((p[1] - vision_blocker_point_radius) * self.map_scale), + ), + ( + (int(p[0] + vision_blocker_point_radius) * self.map_scale), + int((p[1] + vision_blocker_point_radius) * self.map_scale), + ), + self.colors["vision_blockers"], + -1, + ) + alpha = 0.5 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, vb, 1 - alpha, 0) + + def add_creep(self, map_data): + creep = map_data.copy() + + for (y, x), v in np.ndenumerate(self.game.state.creep.data_numpy): + if v: + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + self.colors["creep"], + -1, + ) + + alpha = 0.8 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, creep, 1 - alpha, 0) + + def add_psi(self, map_data): + psi = map_data.copy() + + for psi_provider in self.game.units(PYLON): + psi_center = psi_provider.position + psi_radius = 6.5 + cv2.circle( + map_data, + ( + int(psi_center[0] * self.map_scale), + int(psi_center[1] * self.map_scale), + ), + int(psi_radius * self.map_scale), + self.colors["psi"], + -1, + ) + + alpha = 0.3 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, psi, 1 - alpha, 0) + + def add_minerals(self, map_data): + for mineral in self.game.state.mineral_field: + mine_pos = mineral.position + cv2.rectangle( + map_data, + ( + int((mine_pos[0] - 0.75) * self.map_scale), + int((mine_pos[1] - 0.25) * self.map_scale), + ), + ( + int((mine_pos[0] + 0.75) * self.map_scale), + int((mine_pos[1] + 0.25) * self.map_scale), + ), + self.colors["minerals"], + -1, + ) + + def add_geysers(self, map_data): + for g in self.game.state.vespene_geyser: + g_pos = g.position + cv2.rectangle( + map_data, + ( + int((g_pos[0] - g.radius) * self.map_scale), + int((g_pos[1] - g.radius) * self.map_scale), + ), + ( + int((g_pos[0] + g.radius) * self.map_scale), + int((g_pos[1] + g.radius) * self.map_scale), + ), + self.colors["geysers"], + -1, + ) + + def add_xelnaga(self, map_data): + for unit in self.game.state.watchtowers: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + self.colors["xelnaga"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(22 * self.map_scale), + self.colors["xelnaga"], + 1, + ) + + def add_destructables(self, map_data): + # TODO: make a dictionary that contains all footprints of all destructables to draw them the right way + for unit in self.game.state.destructables: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + self.colors["destructables"], + -1, + ) + + def add_allies(self, map_data): + for unit in self.game.units: + if unit.is_structure: + cv2.rectangle( + map_data, + ( + int((unit.position[0] - unit.radius) * self.map_scale), + int((unit.position[1] - unit.radius) * self.map_scale), + ), + ( + int((unit.position[0] + unit.radius) * self.map_scale), + int((unit.position[1] + unit.radius) * self.map_scale), + ), + self.colors["ally_units"], + -1, + ) + else: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + self.colors["ally_units"], + -1, + ) + + def add_enemies(self, map_data): + for unit in self.game.known_enemy_units: + if unit.is_structure: + cv2.rectangle( + map_data, + ( + int((unit.position[0] - unit.radius) * self.map_scale), + int((unit.position[1] - unit.radius) * self.map_scale), + ), + ( + int((unit.position[0] + unit.radius) * self.map_scale), + int((unit.position[1] + unit.radius) * self.map_scale), + ), + self.colors["enemy_units"], + -1, + ) + else: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + int(unit.radius * self.map_scale), + (0, 0, 255), + -1, + ) + + def add_blips(self, map_data): + for unit in self.game.state.blips: + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale), + int(unit.position[1] * self.map_scale), + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) - 1, + int(unit.position[1] * self.map_scale) - 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) + 1, + int(unit.position[1] * self.map_scale) + 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) + 1, + int(unit.position[1] * self.map_scale) - 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + cv2.circle( + map_data, + ( + int(unit.position[0] * self.map_scale) - 1, + int(unit.position[1] * self.map_scale) + 1, + ), + 1, + self.colors["enemy_units"], + -1, + ) + + def add_visibility(self, map_data): + visibility = map_data.copy() + # gets the min and max heigh of the map for a better contrast + v_min = np.amin(self.game.state.visibility.data_numpy) + v_max = np.amax(self.game.state.visibility.data_numpy) + multiplier = 255 / (v_max - v_min) + + for (y, x), v in np.ndenumerate(self.game.state.visibility.data_numpy): + color = (v - v_min) * multiplier + cv2.rectangle( + map_data, + (x * self.map_scale, y * self.map_scale), + ( + x * self.map_scale + self.map_scale, + y * self.map_scale + self.map_scale, + ), + (color, color, color), + -1, + ) + + alpha = 0.2 # Transparency factor. + + return cv2.addWeighted(map_data, alpha, visibility, 1 - alpha, 0) + + def add_custom_points(self, map_data): + for pointlist, color in self.custom_points.items(): + if isinstance(pointlist, Point2): + cv2.circle( + map_data, + ( + int(pointlist.position[0] * self.map_scale), + int(pointlist.position[1] * self.map_scale), + ), + self.map_scale, + color, + -1, + ) + else: + for point in pointlist: + cv2.circle( + map_data, + ( + int(point.position[0] * self.map_scale), + int(point.position[1] * self.map_scale), + ), + self.map_scale, + color, + -1, + )