def emp_line_strategy(self, game_state): """ Build a line of the cheapest stationary unit so our EMP's can attack from long range. """ # First let's figure out the cheapest unit # We could just check the game rules, but this demonstrates how to use the GameUnit class stationary_units = [FILTER, DESTRUCTOR, ENCRYPTOR] cheapest_unit = FILTER for unit in stationary_units: unit_class = gamelib.GameUnit(unit, game_state.config) if ( unit_class.cost[game_state.BITS] < gamelib.GameUnit(cheapest_unit, game_state.config).cost[ game_state.BITS ] ): cheapest_unit = unit # Now let's build out a line of stationary units. This will prevent our EMPs from running into the enemy base. # Instead they will stay at the perfect distance to attack the front two rows of the enemy base. for x in range(27, 5, -1): game_state.attempt_spawn(cheapest_unit, [x, 11]) # Now spawn EMPs next to the line # By asking attempt_spawn to spawn 1000 units, it will essentially spawn as many as we have resources for game_state.attempt_spawn(EMP, [24, 10], 1000)
def largest_attack_spawn_location(self, game_state, location_options): attacks = [[], []] # Get the damage estimate each path will take for i, attacker in enumerate([SCOUT, DEMOLISHER]): for location in location_options: path = game_state.find_path_to_edge(location) attack = 0 if path: for path_location in path: enemy_structure_in_range = False for attack_loc in game_state.game_map.get_locations_in_range( path_location, gamelib.GameUnit( attacker, game_state.config).attackRange): if game_state.contains_stationary_unit( attack_loc ) and game_state.contains_stationary_unit( attack_loc).player_index == 1: enemy_structure_in_range = True if enemy_structure_in_range: attack += gamelib.GameUnit( attacker, game_state.config).damage_f * ( 3 if attacker == SCOUT else 8) attacks[i].append(attack) return attacks
def get_cheapest_wall(self, game_state): stationary_units = [FILTER, DESTRUCTOR, ENCRYPTOR] cheapest_unit = FILTER cost = 0 for unit in stationary_units: unit_class = gamelib.GameUnit(unit, game_state.config) if unit_class.cost < gamelib.GameUnit(cheapest_unit, game_state.config).cost: cheapest_unit = unit cost = unit_class.cost return cheapest_unit, cost
def find_least_dmg_to_edge(game_state, dmg_thresh): friendly_edges = (game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_LEFT) + game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_RIGHT)) # game_state_sim = game_state bestPath = [1000, []] # 1000 (max) damage, empty path for location in friendly_edges: path = game_state.find_path_to_edge(location) if path_to_enemy_edge(game_state, path): foundPath = True damage = 0 for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage if damage < bestPath[0] and damage <= dmg_thresh: bestPath[0] = damage bestPath[1] = path if bestPath[0] < 1000: cprint(f'Clear, ideal path to enemy edge with {damage} damage') cprint(f'{bestPath[1]}') else: cprint('No path to enemy edge') return bestPath[1]
def least_damage_spawn_location(game_state): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] friendly_edges = (game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_LEFT) + game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_RIGHT)) hostile_edges = (game_state.game_map.get_edge_locations(game_state.game_map.TOP_LEFT) + game_state.game_map.get_edge_locations(game_state.game_map.TOP_RIGHT)) # friendly_edges = [[x, y+1] for x, y in friendly_edges] # Get the damage estimate each path will take for location in friendly_edges: path = game_state.find_path_to_edge(location) damage = 0 if path is None or path[-1] not in hostile_edges: # this needs verification... damages.append(1000) continue else: cprint(f"This is a legit path, starting at {path[0]} and ending at {path[-1]}.") for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage damages.append(damage) # Now just return the location that takes the least damage if min(damages) < 1000: return friendly_edges[damages.index(min(damages))], min(damages) else: return None, 1000
def least_damage_spawn_location(self, game_state, location_options): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) damage = 0 if path is None: return None for path_location in path: unit = game_state.game_map[path_location[0], path_location[1]] if unit is None: continue if len(unit) == 0: continue unit = unit[0] if unit.player_index == 0: return None for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage_i damages.append(damage) # Now just return the location that takes the least damage return location_options[damages.index(min(damages))]
def most_cores_spawn_location(self, game_state, location_options): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) damage = 0 if len(path) < 5: continue for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage #damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage damage -= len(game_state.get_shielders( path_location, 0)) * gamelib.GameUnit( ENCRYPTOR, game_state.config).stability #damage -= len(game_state.get_walls(path_location, 0)) * gamelib.GameUnit(FILTER, game_state.config).stability damages.append(damage) # Now just return the location that takes the least damage if len(damages) > 0: gamelib.debug_write( f'Location for EMP {location_options[damages.index(min(damages))]} will get {min(damages)} points' ) return location_options[damages.index(min(damages))], min(damages)
def reinforce_factory(self, game_state): for location in self.factory_locations: if not gamelib.GameUnit(FACTORY,game_state.config,location).upgraded: succeed = game_state.attempt_upgrade(location) if succeed != 0: self.factory_up_or_build ^= 1 break
def Nth_least_damage_spawn_location(self, game_state, location_options, num=1): """ This function will help us guess the Nth safest location to spawn moving units from. It considers that high chance that our opponent would build defensive units at the safest path on the turn, so we can spawn our units at the 2nd safest location with certain probability. """ damages = [] target_locations = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) target_locations.append(path[-1]) damage = 0 for path_location in path: # Get number of enemy turrets that can attack each location and multiply by turret damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( TURRET, game_state.config).damage_i damages.append(damage) if len(damages) < 2: return [3, 10] n = self.nth_smallest(damages, num) # Now just return the location that takes the nth least damage return location_options[damages.index(n)], target_locations[ damages.index(n)], n
def starter_strategy(self, game_state): """ For defense we will use a spread out layout and some interceptors early on. We will place turrets near locations the opponent managed to score on. For offense we will use long range demolishers if they place stationary units near the enemy's front. If there are no stationary units to attack in the front, we will send Scouts to try and score quickly. """ # deploy basic v-shaped defense structure (if turn < 2 or health is low) if game_state.turn_number <= 2 or game_state.my_health < 10: gamelib.debug_write("Building basic defenses") self.build_v_defences(game_state) # if health is very low, upgrade turrets if game_state.my_health < 10: gamelib.debug_write("Upgrading turrets") self.update_locations(TURRET, game_state) game_state.attempt_upgrade(self.turret_locations) # send interceptors (if enemy MP is greater > 10) if game_state.get_resource(MP, 1) > 10: #gamelib.debug_write("Sending interceptors") #self.send_interceptors(2, game_state) self.update_locations(TURRET, game_state) self.add_walls_to_turrets(self.turret_locations, game_state) # replace hit locations with turrets self.build_reactive_defense(game_state) self.add_walls_to_turrets(self.turret_locations, game_state) # prepare to convert to channel of supports (if SP is high and predicted MP is high) self.update_locations(TURRET, game_state) support_cost = gamelib.GameUnit(SUPPORT, game_state.config).cost[SP] possible_sp = self.calculate_possible_SP(game_state) if game_state.project_future_MP() > 9: gamelib.debug_write("Preparing offensive hit") self.prepare_offensive_hit(game_state) if self.add_supports: self.add_support_channel(game_state) # if we have more than 9 MP and the turn number is close to next group of 10 # then we will send out attack; otherwise we wait for want to save up our MP if game_state.get_resource(MP, 0) > 9 and ( game_state.turn_number % 10 not in [0, 1, 2, 3] or game_state.my_health < 10): # if enemy MP > 10, then we favour sending interceptors #if game_state.get_resource(MP, 1) > 10: # self.send_interceptors(2, game_state) # otherwise send scouts #else: game_state.attempt_spawn(SCOUT, [13, 0], 1000) # check if successful, if not, send demolisher if game_state.get_resource(SP, 0) > 4: wall_line = [[4, 9], [5, 8], [6, 7], [7, 6], [8, 5], [9, 4]] # game_state.attempt_spawn(SUPPORT, wall_line) self.add_walls_to_turrets(self.turret_locations, game_state)
def enemy_least_damage_location(self, game_state): damages = [] enemy_edges = game_state.game_map.get_edge_locations(game_state.game_map.TOP_LEFT) + \ game_state.game_map.get_edge_locations(game_state.game_map.TOP_RIGHT) all_paths = [] for location in enemy_edges: path = game_state.find_path_to_edge(location) all_paths.append(path) damage = 0 if path: for path_location in path: # Get number of enemy turrets that can attack each location and multiply by turret damage damage += len(game_state.get_attackers( path_location, 1)) * gamelib.GameUnit( TURRET, game_state.config).damage_i damages.append(damage) if not damages: return [] probable_attack_path = all_paths[damages.index(min(damages))] filtered_attack_path = [] if probable_attack_path: filtered_attack_path = list( filter(lambda x: True if x[1] <= 13 else False, probable_attack_path)) return filtered_attack_path
def least_damage_spawn_location(self, game_state, location_options): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] target_locations = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) target_locations.append(path[-1]) damage = 0 for path_location in path: # Get number of enemy turrets that can attack each location and multiply by turret damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( TURRET, game_state.config).damage_i damages.append(damage) if len(damages) == 0: return [24, 10] # Now just return the location that takes the least damage return location_options[damages.index( min(damages))], target_locations[damages.index( min(damages))], min(damages)
def least_damage_spawn_location(self, game_state): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ min_damage = float('inf') # Get the damage estimate each path will take ret_loc = None for location in self.offense_locations: if not game_state.can_spawn(PING, location): continue path = game_state.find_path_to_edge(location) if path is None: continue if len(path) == 0: continue if len(path) < 25: continue damage = 0 for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage_i if damage <= min_damage: ret_loc = location min_damage = damage # Now just return the location that takes the least damage return ret_loc
def most_damage_spawn_location(game_state): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] friendly_edges = (game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_LEFT) + game_state.game_map.get_edge_locations(game_state.game_map.BOTTOM_RIGHT)) # friendly_edges = [[x, y+1] for x, y in friendly_edges] # Get the damage estimate each path will take for location in friendly_edges: path = game_state.find_path_to_edge(location) damage = 0 if path is None: damages.append(0) continue for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage damages.append(damage) # Now just return the location that takes the least damage if max(damages) > 0: return friendly_edges[damages.index(max(damages))], max(damages) else: return None, 0
def first_strike(self, game_state): # Get the damage estimate each path will take damages = [] for location in game_state.game_map.get_edge_locations( game_state.game_map.BOTTOM_LEFT): path = game_state.find_path_to_edge(location) damage = 0 if path is None: return for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage # TODO: Get number of shields to subtract!!!! damages.append(damage) if (min(damages) == 0): game_state.attempt_spawn( PING, game_state.game_map.BOTTOM_LEFT(damages.index(min(damages))), 10000) return damages = [] for location in game_state.game_map.get_edge_locations( game_state.game_map.BOTTOM_RIGHT): path = game_state.find_path_to_edge(location) damage = 0 if path is None: return for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage # TODO: Get number of shields to subtract!!!! damages.append(damage) if (min(damages) == 0): game_state.attempt_spawn( PING, game_state.game_map.BOTTOM_RIGHT(damages.index(min(damages))), 10000) return
def optimal_attack_path(self, game_state): # Create fake gamestate game_state_copy = copy.deepcopy(game_state) location_options = game_state_copy.game_map.get_edge_locations(game_state_copy.game_map.BOTTOM_LEFT) + game_state_copy.game_map.get_edge_locations(game_state_copy.game_map.BOTTOM_RIGHT) for loc in self.remove_loc_check: game_state_copy.game_map.remove_unit(loc) damages_taken = [] damages_given_scout = [] damages_given_demolisher = [] # Get the damage estimate each path will take for location in location_options: path = game_state_copy.find_path_to_edge(location) damage_taken = 0 damage_given = 0 for path_location in path: # Get number of enemy turrets that can attack each location and multiply by turret damage damage_taken -= len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(TURRET, game_state.config).damage_i scout_attack_loc = game_state_copy.game_map.get_locations_in_range(path_location, gamelib.GameUnit(SCOUT, game_state_copy.config).attackRange) demolisher_attack_loc = game_state_copy.game_map.get_locations_in_range(path_location, gamelib.GameUnit(DEMOLISHER, game_state_copy.config).attackRange) scout_damage = 0 demolisher_damage = 0 for loc in scout_attack_loc: if game_state_copy.contains_stationary_unit(loc) and loc[1] >= 14: scout_damage += gamelib.GameUnit(SCOUT, game_state_copy.config).damage_f for loc in demolisher_attack_loc: if game_state_copy.contains_stationary_unit(loc) and loc[1] >= 14: demolisher_damage += gamelib.GameUnit(DEMOLISHER, game_state_copy.config).damage_f damages_taken.append(damage_taken) damages_given_scout.append(scout_damage) damages_given_demolisher.append(demolisher_damage) scout_heuristic = [a+b for a, b in zip(damages_taken, damages_given_scout)] demolisher_heuristic = [a+b for a, b in zip(damages_taken, damages_given_demolisher)] # Now just return the location that takes the least damage return game_state_copy.find_path_to_edge(location_options[scout_heuristic.index(min(scout_heuristic))]), game_state_copy.find_path_to_edge(location_options[demolisher_heuristic.index(min(demolisher_heuristic))])
def demolisher_line_strategy(self, game_state): """ Build a line of the cheapest stationary unit so our demolisher can attack from long range. """ # First let's figure out the cheapest unit # We could just check the game rules, but this demonstrates how to use the GameUnit class stationary_units = [WALL, TURRET, SUPPORT] cheapest_unit = WALL for unit in stationary_units: unit_class = gamelib.GameUnit(unit, game_state.config) if unit_class.cost[game_state.MP] < gamelib.GameUnit(cheapest_unit, game_state.config).cost[game_state.MP]: cheapest_unit = unit # Now let's build out a line of stationary units. This will prevent our demolisher from running into the enemy base. # Instead they will stay at the perfect distance to attack the front two rows of the enemy base. for x in range(27, 5, -1): game_state.attempt_spawn(cheapest_unit, [x, 11]) # Now spawn demolishers next to the line # By asking attempt_spawn to spawn 1000 units, it will essentially spawn as many as we have resources for game_state.attempt_spawn(DEMOLISHER, [24, 10], 1000)
def reward_func(self, game_state, unit_type, init_pos, unit_numbers): """ kfz """ path = game_state.find_path_to_edge(init_pos) total_health = unit_numbers * gamelib.GameUnit(unit_type, game_state.config).stability reward = 0 for path_location in path: each_damage = len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage attack_target = game_state.get_target(gamelib.GameUnit(unit_type, game_state.config, 0, None, path_location[0], path_location[1])) if attack_target: total_damage = 12 if unit_type == "EI" else 2 total_damage *= math.ceil(total_health / gamelib.GameUnit(unit_type, game_state.config).stability) attack_reward = min(total_damage / attack_target.stability, 1) if attack_target.unit_type == DESTRUCTOR: attack_reward *= 2 reward += attack_reward total_health -= each_damage reward += math.ceil(total_health / gamelib.GameUnit(unit_type, game_state.config).stability) * (40 + 1 / game_state.CORES) if reward < 30: reward = -1 return reward
def build_defences(self, game_state): num_cores = game_state.get_resource(CORES) for kk in range(len(self.total_defense_locations)): if kk >= 2 and self.num_destructors < 15: break if kk >= 1 and game_state.get_resource(CORES) < 6: return for ii in range(len(self.total_defense_locations[kk])): if self.total_defense_locations[kk][ii] == None: continue for location in self.total_defense_locations[kk][ii]: if ii == 0: game_state.attempt_spawn(FILTER, location) num_cores -= gamelib.GameUnit(FILTER, game_state.config).cost[game_state.CORES] elif ii == 1: game_state.attempt_spawn(DESTRUCTOR, location) num_cores -= gamelib.GameUnit(DESTRUCTOR, game_state.config).cost[game_state.CORES] else: game_state.attempt_spawn(ENCRYPTOR, location) num_cores -= gamelib.GameUnit(ENCRYPTOR, game_state.config).cost[game_state.CORES]
def update_map(self, game_state): # For every location along the barrier that was struck, we decrease the value by 100 for location in self.scored_on_locations: self.map_values[(location[0], location[1])] -= self.damaged_cost_decrement for location in self.enemy_attacker_spawn_locations: path = game_state.find_path_to_edge(location) damage = 0 for path_location in path: # Adding damage done by all destructors that can attack that location damage += len(game_state.get_attackers(path_location, 1)) * \ gamelib.GameUnit(DESTRUCTOR, game_state.config).damage damage += len(game_state.get_attackers_encryptors(path_location, 1)) * \ gamelib.GameUnit(ENCRYPTOR, game_state.config).damage if (path_location in self.map_values): self.map_values[(path_location[0], path_location[1])] -= damage return self.map_values
def replace_defense(self, game_state): # Replace destructor for k in self.damaged_on_locations: location = [k // 100, k % 100] if game_state.contains_stationary_unit(location): unit = game_state.contains_stationary_unit(location) if unit.stability <= gamelib.GameUnit( unit.unit_type, game_state.config).stability / 4: game_state.attempt_remove(location) else: if (location[0] == 25 or location[0] == 2) and location[1] == 12: continue self.build_wall(game_state, DESTRUCTOR, location)
def emp_line_strategy(self, game_state): """ Build a line of the cheapest stationary unit so our EMP's can attack from long range. """ # First let's figure out the cheapest unit # We could just check the game rules, but this demonstrates how to use the GameUnit class stationary_units = [FILTER, DESTRUCTOR, ENCRYPTOR] cheapest_unit = FILTER for unit in stationary_units: unit_class = gamelib.GameUnit(unit, game_state.config) if unit_class.cost[game_state.BITS] < gamelib.GameUnit( cheapest_unit, game_state.config).cost[game_state.BITS]: cheapest_unit = unit # Now let's build out a line of stationary units. This will prevent our EMPs from running into the enemy base. # Instead they will stay at the perfect distance to attack the front two rows of the enemy base. #for x in range(27, 5, -1): # game_state.attempt_spawn(cheapest_unit, [x, 11]) # Now spawn EMPs next to the line # By asking attempt_spawn to spawn 1000 units, it will essentially spawn as many as we have resources for location = [24, 10] path = game_state.find_path_to_edge(location) if path is not None: flag = True for path_location in path: unit = game_state.game_map[path_location[0], path_location[1]] if unit is None: continue if len(unit) == 0: continue unit = unit[0] if unit.player_index == 0: flag = False break if flag: game_state.attempt_spawn(EMP, location, 1000)
def gain_of_attack(self, game_state, number_units, unit_type, location): """ This function computes the weighted gain of a given type of attack starting at a specific location """ path = game_state.find_path_to_edge(location) damage_dealt = 0 turret_damage = gamelib.GameUnit(TURRET, game_state.config).damage_i unit_class = gamelib.GameUnit(unit_type, game_state.config) unit_health = unit_class.health unit_range = unit_class.attackRange remaining_units = number_units total_heath = unit_health * number_units for path_location in path: num_turrets = len(game_state.get_attackers(path_location, 0)) for frame_index in range(int(1 / (unit_class.speed))): total_damage = unit_class.damage_f * remaining_units damage_dealt += min( total_damage, self.total_target_health(game_state, path_location, unit_class.attackRange)) total_heath -= num_turrets * turret_damage remaining_units = (total_heath // unit_health) + 1 return (damage_dealt * weight_damage_enemy + remaining_units * weight_score)
def location_to_damages(self, game_state, location_options): """ This function gives us a list of estimated damages taken when spawning a unit at each location, the damages are ordered in the same order that locations are in location_options """ damages = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) damage = 0 for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage_i damages.append(damage) return damages
def better_spawn_location(self, game_state, location_coordinates): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] # Get the damage estimate each path will take for location in location_coordinates: path = game_state.find_path_to_edge(location) damage = 0 for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(DESTRUCTOR, game_state.config).damage damages.append(damage) # Now just return the location that takes the least damage return location_coordinates[damages.index(min(damages))]
def least_damage_spawn_location(self, game_state, location_options): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. """ damages = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) damage = 0 for path_location in path: damage += len(game_state.get_attackers(path_location, 0)) * gamelib.GameUnit(TURRET, game_state.config).damage_i # maybe a problem here because it assumes all turrets are not upgraded if game_state.contains_stationary_unit(path[-1]): damage += game_state.game_map[path[-1][0], path[-1][1]].health damages.append(damage) # Now just return the location that takes the least damage gamelib.debug_write("lowest damage = " + str(min(damages))) return [location_options[damages.index(min(damages))], min(damages)]
def simulate_emp(state, loc): score = 0 m = state.game_map path = state.find_path_to_edge(loc, m.TOP_RIGHT if loc[0] < 14 else m.TOP_LEFT) for i in path: if has_destructor( state, filter(lambda x: x[1] > 13, m.get_locations_in_range( i, 3))) or i[1] > 13: break unit = gamelib.GameUnit(EMP, state.config, 0, 40, *i) target = state.get_target(unit) if target: target.stability -= 4 if target.stability < 0: m.remove_unit((target.x, target.y)) score += min(4, target.stability + 4) return score
def best_spawn_calculation(self, game_state, location_options): """ This function will help us guess which location is the safest to spawn moving units from. It gets the path the unit will take then checks locations on that path to estimate the path's damage risk. It will also search for what defenses are on the path that it can add (NOT YET ADDED) """ damages = [] # Get the damage estimate each path will take for location in location_options: path = game_state.find_path_to_edge(location) damage = 0 for path_location in path: # Get number of enemy destructors that can attack the final location and multiply by destructor damage damage += len(game_state.get_attackers( path_location, 0)) * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage # TODO: Get number of shields to subtract!!!! damages.append(damage) # Now just return the location that takes the least damage return location_options[damages.index(min(damages))]
def compute_ideal_start(self, game_state): # returns the least damage received location and the most damage dealt location # for each of the starting points # get the path # compute how much damange a given offensive unit can deal # place half at least damage spawn location # place half at most damage dealing location game_map = game_state.game_map least_damage_location = self.least_damage_spawn_location(game_state) most_damage_location = None max_damage = float('-inf') EMP_unit = gamelib.GameUnit(EMP, game_state.config) for starting_location in self.offense_locations: if not game_state.can_spawn(PING, starting_location): continue path = game_state.find_path_to_edge(starting_location) if path is None: continue if len(path) == 0: continue if len(path) < 25: continue damage = 0 units_of_enemy_can_damage = [] for path_location in path: # assume placing EMPs right now for location in game_map.get_locations_in_range( path_location, 4.5): #attack range of the EMP if (len(game_map[location[0], location[1]]) > 0): units_of_enemy_can_damage.extend(game_map[location[0], location[1]]) damage = len(units_of_enemy_can_damage) if damage > max_damage: max_damage = damage most_damage_location = starting_location return least_damage_location, most_damage_location
def best_spawn_location(self, game_state, scrambler_heatmap, score_board): global location_options, fire_param, scrambler_param, bits_save_threshold preferences = [] paths = [] enemy_destr_counts = [] for location in location_options: path = game_state.find_path_to_edge(location) paths.append(path) preference, fire, scram, tough = 0 for path_location in path: [x, y] = path_location enemy_destr_count = len( game_state.get_attackers(path_location, 0)) enemy_destr_counts.append(enemy_destr_count) fire += enemy_destr_count * gamelib.GameUnit( DESTRUCTOR, game_state.config).damage if path_location in scrambler_heatmap: scram += 1 risk = fire * fire_param + scram * scrambler_param + 1 reward = score_board[x] preference = reward / risk preference.append(preference) idx = preferences.index(min(preferences)) return location_options[idx], paths[idx], enemy_destr_counts[idx]