def obs_to_state(self, obs): """ Convert sc2 obs object to a (distance_to_enemy, viking_flying_or_landed) state. :param obs: SC2Env observation :return: """ # Distance own_unit_loc = np.array(get_own_unit_location(obs)) enemy_loc = np.array(get_enemy_unit_location(obs)) dist = np.linalg.norm(own_unit_loc - enemy_loc) rounded_dist = int(round(dist)) # Flying or landed flying = None landed_action_id = internal_id_to_action_id(constants.LAND) can_land = landed_action_id in obs.observation['available_actions'] if can_land: # If we can land we are flying flying = 'flying' else: flying_action_id = internal_id_to_action_id(constants.FLIGHT) can_fly = flying_action_id in obs.observation['available_actions'] if can_fly: # If we can fly we are landed flying = 'landed' else: ValueError("Can neither land nor fly ... ") # Is enemy coming towards us enemy_closing_in = 'enemy_closing_in' if obs.reward > 0 and rounded_dist < 25 else 'enemy_not_attacking' return f'{rounded_dist}/{flying}/{enemy_closing_in}'
def _act(self, obs): state = self.obs_to_state(obs) illegal_internal_action_ids = self._get_illegal_internal_action_ids( obs) sc_action = self.model.select_action(state, illegal_internal_action_ids) if sc_action.internal_id == constants.NO_OP: pass elif sc_action.internal_id == constants.ATTACK_ENEMY: location = get_enemy_unit_location(obs) sc_action.set_location(location) elif sc_action.internal_id == constants.MOVE_TO_ENEMY: raise ValueError("Move to enemy action is illegal for this agent") elif sc_action.internal_id == constants.MOVE_FROM_ENEMY: location = self.get_location_away(obs) sc_action.set_location(location) elif sc_action.internal_id == constants.LAND: pass elif sc_action.internal_id == constants.FLIGHT: pass else: raise NotImplementedError("Unknown action ID received") return sc_action
def get_location_to(self, obs): """ Get the location we want to move towards the enemy. We cannot move 'on' the enemy because that equals attacking :return: x, y """ enemy_x_min, enemy_x_max, enemy_y_min, enemy_y_max = get_enemy_width_and_height( obs) own_unit_x, own_unit_y = get_own_unit_location(obs) enemy_x, enemy_y = get_enemy_unit_location(obs) # Select between 4 quadrants below/above and left/right of the enemy to move to. # We want to move further than the enemy in case we are standing too close to move to a location between our # unit(s) and the enemy if enemy_x >= own_unit_x: x = enemy_x_max + 2 else: x = enemy_x_min - 2 if enemy_y >= own_unit_y: y = enemy_y_max + 2 else: y = enemy_y_min - 2 location_to = self.clip_location((x, y), obs) return location_to
def obs_to_state(obs): """ Convert sc2 obs object to a distance_to_enemy state. :param obs: SC2Env observation :return: """ own_unit_loc = np.array(get_own_unit_location(obs)) enemy_loc = np.array(get_enemy_unit_location(obs)) dist = np.linalg.norm(own_unit_loc - enemy_loc) rounded_dist = int(round(dist)) return rounded_dist
def get_location_away(self, obs): own_location = get_own_unit_location(obs) enemy_location = get_enemy_unit_location(obs) # Distance between units dx = enemy_location[0] - own_location[0] dy = enemy_location[1] - own_location[1] # Move in opposite direction of enemy away_location = (own_location[0] - dx, own_location[1] - dy) # Make sure we don't move outside the screen away_location = self.clip_location(away_location, obs) return away_location
def _act(self, obs): state = self.obs_to_state(obs) sc_action = self.model.select_action(state) if sc_action.internal_id == constants.NO_OP: pass elif sc_action.internal_id == constants.ATTACK_ENEMY: location = get_enemy_unit_location(obs) sc_action.set_location(location) elif sc_action.internal_id == constants.MOVE_TO_ENEMY: location = self.get_location_to(obs) sc_action.set_location(location) elif sc_action.internal_id == constants.MOVE_FROM_ENEMY: location = self.get_location_away(obs) sc_action.set_location(location) else: raise NotImplementedError( f"Unknown action ID {sc_action.internal_id} received") return sc_action