def build_tech_lab_barracks(self, obs): """ Builds a tech lab addon at a barracks. """ new_action = [actions.FUNCTIONS.no_op()] barracks = HelperClass.get_units(self, obs, units.Terran.Barracks) if self.reqSteps == 0: self.reqSteps = 4 elif self.reqSteps == 4: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] elif self.reqSteps == 3: if len(barracks) > 0 and HelperClass.not_in_progress( self, obs, units.Terran.Barracks): new_action = [ actions.FUNCTIONS.select_point( "select", (HelperClass.sigma( barracks[0].x), HelperClass.sigma(barracks[0].y))) ] elif self.reqSteps == 2: if len(barracks) > 0: if HelperClass.is_unit_selected(self, obs, units.Terran.Barracks): if HelperClass.do_action( self, obs, actions.FUNCTIONS.Build_TechLab_Barracks_quick.id): new_action = [ actions.FUNCTIONS.Build_TechLab_Barracks_quick( "now") ] self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def build_reaper(self, obs): new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: new_action = HelperClass.select_all_buildings(obs) if self.reqSteps == 3: if len(obs.observation.multi_select > 0): for i in range(len(obs.observation.multi_select)): if obs.observation.multi_select[i].unit_type == units.Terran.Barracks or \ obs.observation.multi_select[i].unit_type == units.Terran.BarracksTechLab or \ obs.observation.multi_select[i].unit_type == units.Terran.BarracksReactor: new_action = [ actions.FUNCTIONS.select_unit( "select_all_type", i) ] break if self.reqSteps == 2: if HelperClass.is_unit_selected(self, obs, units.Terran.Barracks) or \ HelperClass.is_unit_selected(self, obs, units.Terran.BarracksTechLab) or \ HelperClass.is_unit_selected(self, obs, units.Terran.BarracksReactor): if HelperClass.do_action( self, obs, actions.FUNCTIONS.Train_Reaper_quick.id): new_action = [actions.FUNCTIONS.Train_Reaper_quick("now")] # One step is being intentionally left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def build_starport(self, obs): """ Builds a starport. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] elif self.reqSteps == 3: new_action = HelperClass.select_scv(self, obs) elif self.reqSteps == 2: # Moves camera twice because select_scv can also move camera new_action = [actions.FUNCTIONS.move_camera(self.base_location)] elif self.reqSteps == 1: coordinates = BuildOrders.find_placement(self, obs, building_radius=6, maximum_searches=10, sampling_size=9) if coordinates is not None: new_action = HelperClass.place_building( self, obs, units.Terran.Starport, coordinates[0], coordinates[1]) self.reqSteps -= 1 ActionSingleton().set_action(new_action) """
def count_army(self, obs): """Selects all army units and counts them. Currently only counts marines. :param obs: The observer. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 2 if self.reqSteps == 2: self.reqSteps = 1 if actions.FUNCTIONS.select_army.id in obs.observation.available_actions: new_action = [actions.FUNCTIONS.select_army("select")] else: # Fulhack, men detta gör så att attack selector alltid kan göra detta först. self.reqSteps = -1 elif self.reqSteps == 1: if HelperClass.is_unit_selected(self, obs, units.Terran.Marine): self.marine_count = 0 for i in range(len(obs.observation.multi_select)): if obs.observation.multi_select[ i].unit_type == units.Terran.Marine: self.marine_count += 1 # Fulhack, men detta gör så att attack selector alltid kan göra detta först. self.reqSteps = -1 ActionSingleton().set_action(new_action)
def find_all_command_centers(self, obs, expo_locations): if len(self.command_centers_pos) == 0: for camera_coord in expo_locations: if HelperClass.check_minimap_for_units(self, obs, camera_coord): self.command_centers_pos.append(camera_coord) if len(self.command_centers_pos) != self.num_command_centers: if self.camera_moved: if len(HelperClass.get_units(self, obs, units.Terran.CommandCenter)) == 0: del self.command_centers_pos[self.command_center_counting_index] else: self.command_center_counting_index += 1 if not self.camera_moved: self.camera_moved = True if len(self.command_centers_pos) == self.num_command_centers \ or self.command_center_counting_index >= len(self.command_centers_pos): self.all_command_centers_found = True self.camera_moved = False else: camera_coord = self.command_centers_pos[self.command_center_counting_index] new_action = [actions.FUNCTIONS.move_camera(camera_coord)] ActionSingleton().set_action(new_action) else: self.all_command_centers_found = True return
def retreat(self, obs, location=None): """Selects all army units and issues a move order. :param obs: The observer. :param location: The desired location to move to [y, x] in minimap coordinates. If None, it defaults to base_location. """ new_action = [actions.FUNCTIONS.no_op()] if location is None: location = [32, 32] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 3: if actions.FUNCTIONS.select_army.id in obs.observation.available_actions: new_action = [actions.FUNCTIONS.select_army("select")] if self.reqSteps == 2: if actions.FUNCTIONS.Move_minimap.id in obs.observation.available_actions: self.action_finished = True new_action = [ actions.FUNCTIONS.Move_minimap("now", [location[0], location[1]]) ] # One step is being intentionally left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def no_op(self, obs): new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def build_barracks(self, obs, build_location): """ Builds a barracks. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] elif self.reqSteps == 3: new_action = HelperClass.select_scv(self, obs) elif self.reqSteps == 2: # Moves camera twice because select_scv can also move camera new_action = [actions.FUNCTIONS.move_camera(self.base_location)] elif self.reqSteps == 1: place_location = BuildOrders.find_placement_buildplacment \ (self, obs, building_radius=7, build_locations=build_location) if place_location is not None: new_action = HelperClass.place_building( self, obs, units.Terran.Barracks, place_location[0], place_location[1]) self.reqSteps -= 1 ActionSingleton().set_action(new_action) return coordinates = BuildOrders.find_placement(self, obs, building_radius=6, maximum_searches=1000, sampling_size=1) if coordinates is not None: new_action = HelperClass.place_building( self, obs, units.Terran.Barracks, coordinates[0], coordinates[1]) self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def build_supply_depot(self, obs, build_location): """ Builds a supply depot. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] if self.reqSteps == 3: HelperClass.get_current_minimap_location(obs) new_action = HelperClass.select_scv(self, obs) if self.reqSteps == 2: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] if self.reqSteps == 1: place_location = BuildOrders.find_placement_buildplacment \ (self, obs, building_radius=2, build_locations=build_location) if place_location is not None: new_action = HelperClass.place_building( self, obs, units.Terran.SupplyDepot, place_location[0], place_location[1]) ActionSingleton().set_action(new_action) self.reqSteps -= 1 return for loop in range(20): x = random.randint(2, 82) y = random.randint(2, 82) if BuildOrders.is_valid_placement(self, obs, (x, y), building_radius=2): new_action = HelperClass.place_building( self, obs, units.Terran.SupplyDepot, x, y) break self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def update_state(self, bot_obj, obs): """ Updates the state and adds up to 1 production facility to control group. Always takes 4 steps to execute. :param bot_obj: The agent :param obs: The observation :return: Actions """ new_action = [actions.FUNCTIONS.no_op()] # No action by default if bot_obj.reqSteps == 0: bot_obj.reqSteps = 3 new_action = [actions.FUNCTIONS.select_control_group("recall", 9)] # Section for adding unselected production building to control group 9. # It only adds one building per state update to keep state update lengths consistent. # When at this stage, control group 9 should be selected. # This section should be ran even when the control group is correct. elif bot_obj.reqSteps == 3: unselected_production = self.get_unselected_production_buildings(obs, on_screen=False) if len(unselected_production) > 0: unit = random.choice(unselected_production) new_action = HelperClass.move_screen(obs, (unit.x, unit.y)) bot_obj.reqSteps = 2 elif bot_obj.reqSteps == 2: unselected_production = self.get_unselected_production_buildings(obs, on_screen=True) if len(unselected_production) > 0: unit = random.choice(unselected_production) new_action = [actions.FUNCTIONS.select_point( "select", (HelperClass.sigma(unit.x+random.randint(0, 3)), HelperClass.sigma(unit.y+random.randint(0, 3))))] bot_obj.reqSteps = 1 elif bot_obj.reqSteps == 1: # single_select is an array of zeros if nothing is selected. # The following line checks for when hp > 0 (i.e. a unit is actually selected) if obs.observation.single_select[0][2] > 0: if (obs.observation.single_select[0].unit_type == units.Terran.CommandCenter or obs.observation.single_select[0].unit_type == units.Terran.Barracks or obs.observation.single_select[0].unit_type == units.Terran.Factory or obs.observation.single_select[0].unit_type == units.Terran.Starport): new_action = [actions.FUNCTIONS.select_control_group("append", 9)] bot_obj.reqSteps = 0 # Update the score and reward bot_obj.game_state_updated = True ActionSingleton().set_action(new_action)
def scout(self, obs): """Selects a random SCV and issues a move order to an enemy base. :param obs: The observer. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: if obs.observation.player.idle_worker_count > 0: new_action = [ actions.FUNCTIONS.select_idle_worker( "select", obs, units.Terran.SCV) ] elif actions.FUNCTIONS.move_camera.id in obs.observation.available_actions: new_action = [ HelperClass.move_camera_to_base_location(self, obs) ] if self.reqSteps == 3: if not HelperClass.is_unit_selected(self, obs, units.Terran.SCV): new_action = HelperClass.select_scv(self, obs) if self.reqSteps == 2: if HelperClass.is_unit_selected(self, obs, units.Terran.SCV): if actions.FUNCTIONS.Move_minimap.id in obs.observation.available_actions: if self.start_top: self.scout_loc = random.choice( Coordinates.EXPO_LOCATIONS2 + [Coordinates.START_LOCATIONS[1]]) else: self.scout_loc = random.choice( Coordinates.EXPO_LOCATIONS2 + [Coordinates.START_LOCATIONS[0]]) self.last_scout = self.steps self.action_finished = True new_action = [ actions.FUNCTIONS.Move_minimap("now", self.scout_loc) ] # One step is being intentionally left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def transform_vikings_to_air(self, obs): """ Transforms all available Vikings to their air mode (Fighter mode) :param obs: The observer. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: if actions.FUNCTIONS.select_army.id in obs.observation.available_actions: new_action = [actions.FUNCTIONS.select_army("select")] if self.reqSteps == 3: vikings_ground = [ vikings for vikings in obs.observation.multi_select if vikings.unit_type == units.Terran.VikingAssault ] if len(vikings_ground) > 0: if HelperClass.do_action(self, obs, actions.FUNCTIONS.select_unit.id): for i in range(len(obs.observation.multi_select)): if obs.observation.multi_select[ i].unit_type == units.Terran.VikingAssault: new_action = [ actions.FUNCTIONS.select_unit( "select_all_type", i) ] break if self.reqSteps == 2: if HelperClass.do_action( self, obs, actions.FUNCTIONS.Morph_VikingFighterMode_quick.id): new_action = [ actions.FUNCTIONS.Morph_VikingFighterMode_quick("now") ] self.action_finished = True # One step is being intentionally left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def step(self, obs): super(TestAttack, self).step(obs) action = actions.FUNCTIONS.no_op() if obs.first(): start_y, start_x = (obs.observation.feature_minimap.player_relative == features.PlayerRelative.SELF).nonzero() xmean = start_x.mean() ymean = start_y.mean() self.base_location = (xmean, ymean) if self.reqSteps == 0 and self.has_attacked: self.attacking = False if self.reqSteps == 0 and not self.has_attacked: self.attacking = True self.has_attacked = True if self.attacking: ArmyControlController.attack(self, obs) action = ActionSingleton().get_action() return action
def step(self, obs, epsilon, episode): super(AiBot, self).step(obs) self.epsilon = epsilon self.episode = episode # first step if obs.first(): # Räknaren resettas inte mellan games/episoder. Vet ej om detta är en bra lösning. self.steps = 0 start_y, start_x = (obs.observation.feature_minimap.player_relative == features.PlayerRelative.SELF).nonzero() xmean = start_x.mean() ymean = start_y.mean() self.base_location = (xmean, ymean) if xmean <= 31 and ymean <= 31: self.start_top = True self.attack_coordinates = Coordinates.START_LOCATIONS[1] self.base_location = Coordinates.START_LOCATIONS[0] else: self.start_top = False self.attack_coordinates = Coordinates.START_LOCATIONS[0] self.base_location = Coordinates.START_LOCATIONS[1] self.game_state = State(self) HelperClass.find_the_camera_postion(self, obs) if HelperClass.check_building_at_position( self, obs, Buildsingelton().get_location()): HelperClass.move_camera_to_base_location(self, obs) self.build_States = BuildFacade.set_up(self, obs, self.base_location) self.build_state_reward = self.build_States[0][0] self.build_state = self.build_States[0][1] Buildsingelton().set_location(self.build_state) self.action_state = self.build_States[0][2] self.old_score = self.build_States[1] self.build_state = self.build_States[2] self.build_space = len(self.build_state) #self.build_network = BuildNetwork(self.build_state_reward,self.build_state, self.action_state, epsilon) #BuildNetwork.predict_neural_network(self.build_network, self.build_States) self.build_location = Buildsingelton().get_location() action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0 or self.reqSteps == -1: self.earlier_action = self.next_action self.next_action = Selector.selector(self, obs) if self.next_action == "updateState": self.game_state.update_state(self, obs) action = ActionSingleton().get_action() if self.next_action == "expand": BuildOrdersController.build_expand(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_scv": # build scv UnitBuildOrdersController.build_scv(self, obs) action = ActionSingleton().get_action() elif self.next_action == "distribute_scv": # Har inte gjort någon controller än if self.reqSteps == 0: self.DistributeSCVInstance = DistributeSCV() self.DistributeSCVInstance.distribute_scv(self, obs, self.base_location) action = ActionSingleton().get_action() elif self.next_action == "build_supply_depot": # build supply depot BuildOrdersController.build_supply_depot(self, obs, self.build_location) action = ActionSingleton().get_action() elif self.next_action == "build_barracks": BuildOrdersController.build_barracks(self, obs, self.build_location) action = ActionSingleton().get_action() elif self.next_action == "build_refinery": BuildOrdersController.build_refinery(self, obs) action = ActionSingleton().get_action() elif self.next_action == "return_scv": BuildOrdersController.return_scv(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_marine": UnitBuildOrdersController.train_marines(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_marauder": UnitBuildOrdersController.train_marauder(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_reaper": UnitBuildOrdersController.train_reaper(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_hellion": UnitBuildOrdersController.train_hellion(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_medivac": UnitBuildOrdersController.train_medivac(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_viking": UnitBuildOrdersController.train_viking(self, obs) action = ActionSingleton().get_action() elif self.next_action == "army_count": ArmyControlController.count_army(self, obs) action = ActionSingleton().get_action() elif self.next_action == "attack": ArmyControlController.attack(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_factory": BuildOrdersController.build_factory(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_starport": BuildOrdersController.build_starport(self, obs) action = ActionSingleton().get_action() elif self.next_action == "build_tech_lab_barracks": BuildOrdersController.build_tech_lab_barracks(self, obs) action = ActionSingleton().get_action() elif self.next_action == "retreat": ArmyControlController.retreat(self, obs) action = ActionSingleton().get_action() elif self.next_action == "scout": ArmyControlController.scout(self, obs) action = ActionSingleton().get_action() elif self.next_action == "transform_vikings_to_ground": ArmyControlController.transform_vikings_to_ground(self, obs) action = ActionSingleton().get_action() elif self.next_action == "transform_vikings_to_air": ArmyControlController.transform_vikings_to_air(self, obs) action = ActionSingleton().get_action() elif self.next_action == "no_op": HelperClass.no_op(self, obs) action = ActionSingleton().get_action() return action[0]
def build_refinery(self, obs): """ Builds a refinery in any base with a command center. """ # TODO: Maybe should check for depleted geysers # TODO: Once stumbled upon a bug where it started to build refineries in the middle of the map. Haven't tried # to fix it. new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: new_action = [actions.FUNCTIONS.move_camera(self.base_location)] if self.reqSteps == 3: new_action = HelperClass.select_scv(self, obs) # This step finds a vacant vespene geyser near a command center and moves the camera there. # The center of a Command Center must be about 8 in-game units away from a geyser. # The feature screen is 24x24 in-game units or 84x84 screen units. # With a margin, a geyser will be less than 9.5 * 84/24 screen units from its Command Center (or half a screen) # That's how this code judges if a geyser belongs to a base. if self.reqSteps == 2: geyser_distance = (9.5 * 84 / 24)**2 all_geysers = [ u for u in obs.observation.raw_units if u.unit_type == units.Neutral.VespeneGeyser ] all_refineries = [ u for u in obs.observation.raw_units if u.unit_type == units.Terran.Refinery and u.alliance == 1 ] all_command_centers = [ u for u in obs.observation.raw_units if u.unit_type == units.Terran.CommandCenter and u.alliance == 1 ] selected_geyser = [] if len(all_command_centers) > 0: cc_pos = [(cc.x, cc.y) for cc in all_command_centers] if len(all_refineries) > 0: refinery_pos = [(ref.x, ref.y) for ref in all_refineries] # Find CCs with at least one vacant geyser for i in range(len(all_command_centers)): cc = cc_pos[i] base_refineries = 0 # Finds the number of refineries belonging to a CC for j in range(len(all_refineries)): if (cc[0] - refinery_pos[j][0])**2 + ( cc[1] - refinery_pos[j][1])**2 < geyser_distance: base_refineries += 1 if base_refineries == 2: break # Equivalent to there being a vacant geyser near the CC if base_refineries < 2: geyser_pos = [(geyser.x, geyser.y) for geyser in all_geysers] for j in range(len(all_geysers)): if (cc[0] - geyser_pos[j][0])**2 + ( cc[1] - geyser_pos[j][1])**2 < geyser_distance: selected_geyser = geyser_pos[j] break if selected_geyser: break # Trivial case: there are no refineries so just pick any suitable geyser else: cc = random.choice(cc_pos) if len(all_geysers) > 0: geyser_pos = [(geyser.x, geyser.y) for geyser in all_geysers] for i in range(len(all_geysers)): if (cc[0] - geyser_pos[i][0])**2 + ( cc[1] - geyser_pos[i][1])**2 < geyser_distance: selected_geyser = geyser_pos[i] if selected_geyser: new_action = HelperClass.move_screen(obs, selected_geyser) # At this point there should be a vacant geyser on the screen (or none at all if last step failed). if self.reqSteps == 1: geysers = [ u for u in obs.observation.feature_units if u.unit_type == units.Neutral.VespeneGeyser ] refineries = [ u for u in obs.observation.feature_units if u.unit_type == units.Terran.Refinery and u.alliance == 1 ] if len(refineries) == 0 and len(geysers) > 0: new_action = HelperClass.place_building( self, obs, units.Terran.Refinery, geysers[0].x, geysers[0].y) elif len(refineries) == 1 and len(geysers) == 2: geyser_loc_1 = (geysers[0].x, geysers[0].y) geyser_loc_2 = (geysers[1].x, geysers[1].y) if geyser_loc_1[0] == refineries[0].x and geyser_loc_1[ 1] == refineries[0].y: new_action = HelperClass.place_building( self, obs, units.Terran.Refinery, geyser_loc_2[0], geyser_loc_2[1]) else: new_action = HelperClass.place_building( self, obs, units.Terran.Refinery, geyser_loc_1[0], geyser_loc_1[1]) self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def attack(self, obs, location=None): """Selects all army units and issues an attack order on the closest enemy. It checks for enemies using the minimap. It also counts the army. :param obs: The observer. :param location: The desired location to attack [x, y] in minimap coordinates. If None, it attacks the closest enemy """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: if actions.FUNCTIONS.select_army.id in obs.observation.available_actions: new_action = [actions.FUNCTIONS.select_army("select")] if self.reqSteps == 3: if location is None: distance = [] enemy_y, enemy_x = ( obs.observation.feature_minimap.player_relative == features.PlayerRelative.ENEMY).nonzero() if len(enemy_y) > 0: for i in range(len(enemy_y)): distance.append( np.power(enemy_x[i] - self.base_location[1], 2) + np.power(enemy_y[i] - self.base_location[0], 2)) index_min = min(range(len(distance)), key=distance.__getitem__) location = [enemy_x[index_min], enemy_y[index_min]] else: location = self.attack_coordinates if actions.FUNCTIONS.move_camera.id in obs.observation.available_actions: new_action = [actions.FUNCTIONS.move_camera(location)] if self.reqSteps == 2: has_attack_point = False screen_location = [0, 0] while not has_attack_point: x = random.randint(20, 60) y = random.randint(20, 60) if obs.observation.feature_screen[5][y][ x] == 0: # Finds a point without any units screen_location = [x, y] has_attack_point = True if actions.FUNCTIONS.Attack_screen.id in obs.observation.available_actions: self.action_finished = True new_action = [ actions.FUNCTIONS.Attack_screen("now", screen_location) ] # One step is being intentionally left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def return_scv(self, obs): """ Returns an idle SCV to mining. It tries to populate refineries first. Checks other bases if the main base has depleted its resources. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.reqSteps = 4 if self.reqSteps == 4: if obs.observation.player.idle_worker_count > 0: new_action = [ actions.FUNCTIONS.select_idle_worker( "select", obs, units.Terran.SCV) ] # Finds a suitable base to send the SCV to. if self.reqSteps == 3: command_centers = [ u for u in obs.observation.raw_units if u.alliance == 1 and u.unit_type == units.Terran.CommandCenter and u.build_progress == 100 and u.ideal_harvesters > 0 ] undermanned_command_centers = [ u for u in command_centers if u.assigned_harvesters / u.ideal_harvesters < 0 ] undermanned_refineries = [ u for u in obs.observation.raw_units if u.alliance == 1 and u.unit_type == units.Terran.Refinery and u.build_progress == 100 and u.assigned_harvesters < 3 ] if len(undermanned_refineries) > 0: refinery = random.choice(undermanned_refineries) new_action = HelperClass.move_screen(obs, (refinery.x, refinery.y)) elif len(undermanned_command_centers) > 0: command_center = random.choice(undermanned_command_centers) new_action = HelperClass.move_screen( obs, (command_center.x, command_center.y)) elif len(command_centers) > 0: command_center = random.choice(command_centers) new_action = HelperClass.move_screen( obs, (command_center.x, command_center.y)) # Should be at a base now. if self.reqSteps == 2: undermanned_refineries = [ u for u in obs.observation.feature_units if u.alliance == 1 and u.unit_type == units.Terran.Refinery and u.build_progress == 100 and u.assigned_harvesters < 3 ] minerals = [ u for u in obs.observation.feature_units if (u.unit_type == units.Neutral.MineralField or u.unit_type == units.Neutral.MineralField750 or u.unit_type == units.Neutral.RichMineralField or u.unit_type == units.Neutral.RichMineralField750) ] if len(undermanned_refineries) > 0: refinery = undermanned_refineries[0] if HelperClass.do_action( self, obs, actions.FUNCTIONS.Harvest_Gather_screen.id): new_action = [ actions.FUNCTIONS.Harvest_Gather_screen( "now", (HelperClass.sigma( refinery.x), HelperClass.sigma(refinery.y))) ] self.action_finished = True elif len(minerals) > 0: mineral = minerals[0] if HelperClass.do_action( self, obs, actions.FUNCTIONS.Harvest_Gather_screen.id): new_action = [ actions.FUNCTIONS.Harvest_Gather_screen( "now", (HelperClass.sigma( mineral.x), HelperClass.sigma(mineral.y))) ] self.action_finished = True # There's one step left (reqSteps == 1) that's intentionally being left blank. self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def expand(self, obs): """ Builds a command center at a suitable, empty base. Doesn't build in the main bases. """ new_action = [actions.FUNCTIONS.no_op()] if self.reqSteps == 0: self.expo_loc = 0 self.reqSteps = 4 if self.reqSteps == 4: # move to base new_action = [HelperClass.move_camera_to_base_location(self, obs)] if self.reqSteps == 3: # select scv command_scv = HelperClass.get_units(self, obs, units.Terran.SCV) if len(command_scv) > 0 and not HelperClass.is_unit_selected( self, obs, units.Terran.SCV): if (obs.observation.player.idle_worker_count > 0): new_action = [ actions.FUNCTIONS.select_idle_worker( "select", obs, units.Terran.SCV) ] else: command = random.choice(command_scv) new_action = [ actions.FUNCTIONS.select_point( "select", (HelperClass.sigma( command.x), HelperClass.sigma(command.y))) ] # This part finds a vacant expansion location if self.reqSteps == 2: camera_pos = HelperClass.get_current_minimap_location(obs) if self.start_top is not None and not self.start_top: expansions_minimap = Coordinates.EXPO_LOCATIONS2 expansions_screen = Coordinates.CC_LOCATIONS2 else: expansions_minimap = Coordinates.EXPO_LOCATIONS expansions_screen = Coordinates.CC_LOCATIONS # This should be compatible with the coordinates gotten from raw_units expansions_relative_screen = [ ((a[0][0] - camera_pos[0]) * (200 * 84 / (24 * 64)) + a[1][0], (a[0][1] - camera_pos[1]) * (200 * 84 / (24 * 64)) + a[1][1]) for a in list(zip(expansions_minimap, expansions_screen)) ] cc = [ u for u in obs.observation.raw_units if (u.unit_type == units.Terran.CommandCenter or u.unit_type == units.Terran.OrbitalCommand or u.unit_type == units.Terran.PlanetaryFortress) ] for i in range(len(expansions_relative_screen)): if len(cc) > 0: vacant = True for j in range(len(cc)): # 10 is an arbitrary screen length. if (abs(cc[j].x - expansions_relative_screen[i][0]) < 10 and abs(cc[j].y - expansions_relative_screen[i][1]) < 10): vacant = False break if vacant: new_action = [ actions.FUNCTIONS.move_camera( expansions_minimap[i]) ] self.expo_loc = i break if self.reqSteps == 1: if self.expo_loc is not None: if self.start_top: t = Coordinates.CC_LOCATIONS[self.expo_loc] else: t = Coordinates.CC_LOCATIONS2[self.expo_loc] if HelperClass.do_action( self, obs, actions.FUNCTIONS.Build_CommandCenter_screen.id): new_action = HelperClass.place_building( self, obs, units.Terran.CommandCenter, t[0], t[1]) self.expo_loc = None self.reqSteps -= 1 ActionSingleton().set_action(new_action)
def distribute_scv(self, obj, obs, base_location): # Use State class to get num expansions later new_action = [actions.FUNCTIONS.no_op()] # No action by default steps_needed = 2 # Actions needed at each Command Center if obj.reqSteps == 0: obj.reqSteps = 1 self.num_command_centers = obj.game_state.units_amount[units.Terran.CommandCenter.value] if not self.all_command_centers_found: all_expo_locations = [base_location] + Coordinates.EXPO_LOCATIONS self.find_all_command_centers(obs, all_expo_locations) if not self.all_command_centers_found: return pos = self.command_centers_pos[self.curr_CC] if self.curr_step % steps_needed == 0: # If all actions for this Command Center are performed, move the if not self.camera_moved: # camera and increment/reset required variables new_action = [actions.FUNCTIONS.move_camera(pos)] self.curr_step -= 1 self.curr_CC -= 1 self.camera_moved = True self.num_CC_minerals_incremented = False if not self.all_refineries_checked: self.first_scv_selected = False elif self.camera_moved: self.camera_moved = False # If on the first loop through expo locations and there is a command center, add this to the total num # if self.curr_step < 2*len(command_centers_pos) and len(command_centers) > 0: #self.num_command_centers += 1 elif self.curr_step % steps_needed == 1: # command_centers = self.get_units_by_type(obs, units.Terran.CommandCenter) if len(command_centers) > 0: # Check that command center exists command_center = command_centers[0] if not self.all_refineries_checked: refineries = self.get_units_by_type(obs, units.Terran.Refinery) refineries_not_ideal = [refinery for refinery in refineries # Get refineries with non-desired amount of SCV:s if refinery.assigned_harvesters != self.refinery_desired_harvesters and refinery.build_progress == 100] if len(refineries_not_ideal) > 0: refinery = refineries_not_ideal[0] # Pick one of the refineries # Calculate the difference between the current amount of SCV:s and the desired amount refinery_scv_ideal_diff = refinery.assigned_harvesters - self.refinery_desired_harvesters # Check how many units are selected currently units_selected = [ unit for unit in obs.observation.feature_units if unit.is_selected] num_units_selected = len(units_selected) # Check if this refinery has too few SCV:s if refinery_scv_ideal_diff < 0 and command_center.assigned_harvesters > self.min_num_mineral_harvesters: # If fewer than the number of SCV:s missing are selected, select from mineral line if num_units_selected < abs(refinery_scv_ideal_diff) or not self.first_scv_selected: # Check if first SCV for this refinery has been selected. # If so, use "toggle", otherwise "select". if not self.first_scv_selected: action_type = "select" self.first_scv_selected = True else: action_type = "toggle" new_action = self.select_single_scv_at_minerals( obs, action_type, (refinery.x, refinery.y)) # If more than the number of SCV:s missing are selected, deselect at index 0 (first position) elif num_units_selected > abs(refinery_scv_ideal_diff): new_action = self.deselect_at_index(obs, 0) self.first_scv_selected = False # If the right amount of SCV:s are selected, assign these to harvest at the refinery elif num_units_selected == abs(refinery_scv_ideal_diff): if refinery.x > 0 and refinery.y > 0 and refinery.x < 84 and refinery.y < 84: new_action = [actions.FUNCTIONS.Harvest_Gather_screen( "now", (refinery.x, refinery.y))] self.first_scv_selected = False # Check if this refinery has too many SCV:s elif refinery_scv_ideal_diff > 0: # Check if the number of SCV:s selected is fewer than the amount too many. # Also check if the first SCV from this refinery has been selected, otherwise select it. if num_units_selected < refinery_scv_ideal_diff or self.first_scv_selected: # To make sure SCV:s harvesting at the refinery are selected, select the closest SCV scvs_on_screen = self.get_units_by_type(obs, units.Terran.SCV) min_dist = 100 scv_selected = None for scv in scvs_on_screen: dist = (scv.x - refinery.x) ** 2 + (scv.y - refinery.y) ** 2 if dist < min_dist: min_dist = dist scv_selected = scv # Check if first SCV for this refinery has been selected. # If so, use "toggle", otherwise "select". if not self.first_scv_selected: action_type = "select" self.first_scv_selected = True else: action_type = "toggle" new_action = [actions.FUNCTIONS.select_point( action_type, (scv_selected.x, scv_selected.y))] # Check if the number of SCV:s selected is more than the amount too many. If so, deselect. elif num_units_selected > refinery_scv_ideal_diff: new_action = self.deselect_at_index(obs, 0) self.first_scv_selected = False # Check if the number of SCV:s selected is the amount too many. If so, send to harvest minerals elif num_units_selected == refinery_scv_ideal_diff: minerals_on_screen = self.get_units_by_type( obs, units.Neutral.MineralField) if len(minerals_on_screen) > 0: mineral = random.choice(minerals_on_screen) new_action = [actions.FUNCTIONS.Harvest_Gather_screen( "now", (mineral.x, mineral.y))] self.first_scv_selected = False # If refinery has the right amount of SCV:s, reset the first selected variable else: self.first_scv_selected = False # If code gets here, this section needs to be repeated at least one more time, so subtract 1 # from the iteration variable if refinery_scv_ideal_diff > 0 or command_center.assigned_harvesters > self.min_num_mineral_harvesters: self.curr_step -= 1 # Check if all refineries are checked for the current Command Center if (len(refineries_not_ideal) == 0 or command_center.assigned_harvesters <= self.min_num_mineral_harvesters) \ and not self.all_refineries_checked: self.num_CC_refineries_checked += 1 # Check if all refineries are checked for all Command Centers if (len(refineries_not_ideal) == 0 or command_center.assigned_harvesters <= self.min_num_mineral_harvesters) \ and self.num_CC_refineries_checked >= self.num_command_centers \ and not self.all_refineries_checked: self.all_refineries_checked = True # Check if all refineries for all Command Centers are checked. If so, start distributing mineral SCV:s if self.all_refineries_checked: # Check if all Command Centers have less than maximum amount of mineral harvesting SCV:s if abs(self.num_CC_minerals_checked) != self.num_command_centers: # Calculate the difference between the assigned and ideal amount of mineral harvesting SCV:s scv_ideal_diff = command_center.assigned_harvesters - command_center.ideal_harvesters if obs.observation.single_select[0][0] != 0: num_units_selected = 1 else: num_units_selected = len(obs.observation.multi_select) # Check if number of SCV:s is more than ideal if scv_ideal_diff > 0: if not self.num_CC_minerals_incremented: if self.num_CC_minerals_checked < 0: self.num_CC_minerals_checked = 0 self.num_CC_minerals_checked += 1 self.num_CC_minerals_incremented = True if not self.first_scv_selected: action_type = "select" self.first_scv_selected = True new_action = self.select_single_scv_at_minerals( obs, action_type, "mean") else: action_type = "toggle" if num_units_selected < scv_ideal_diff: new_action = self.select_single_scv_at_minerals( obs, action_type, "mean") elif num_units_selected > scv_ideal_diff: new_action = self.deselect_at_index(obs, 0) if num_units_selected != scv_ideal_diff: # If the right amount is not selected, loop again self.curr_step -= 1 elif scv_ideal_diff <= 0: # Check if number of SCV:s is less than or equal to ideal amount if not self.num_CC_minerals_incremented: if self.num_CC_minerals_checked > 0: self.num_CC_minerals_checked = 0 self.num_CC_minerals_checked -= 1 self.num_CC_minerals_incremented = True # Check if number of SCV:s is less than ideal if scv_ideal_diff < 0 and self.first_scv_selected: # Check if number selected is more than the amount missing. If so, deselect. if num_units_selected > abs(scv_ideal_diff): new_action = self.deselect_at_index(obs, 0) self.curr_step -= 1 # If the amount selected is not more than the amount missing but more than 1, send # these SCV:s to harvest at this Command Center elif num_units_selected > 0: minerals_on_screen = self.get_units_by_type( obs, units.Neutral.MineralField) mineral = random.choice(minerals_on_screen) new_action = [ actions.FUNCTIONS.Harvest_Gather_screen("now", [mineral.x, mineral.y])] self.first_scv_selected = False # Check if all Command Centers have less than maximum amount of mineral harvesting SCV:s elif abs(self.num_CC_minerals_checked) == self.num_command_centers\ and self.curr_step >= 2*len(self.command_centers_pos): self.all_CC_checked = True self.curr_step += 1 if self.curr_step % steps_needed == 0: self.curr_CC += 1 if self.curr_CC == len(self.command_centers_pos): self.curr_CC = 0 if self.all_CC_checked: # or self.curr_step > 600 new_action = [actions.FUNCTIONS.no_op()] obj.action_finished = True obj.reqSteps = 0 ActionSingleton().set_action(new_action) return