def build_reactive_defence(state: gamelib.AdvancedGameState, damaged_locs): """ Builds reactive defence according to the provided damaged_locs. :param state: current game state. :param damaged_locs: (list) locations of damaged units. Will define where defence units will be spawned. """ num_funded_destructors = int(state.get_resource(state.CORES) // 4) if num_funded_destructors < len(damaged_locs): # If there are less funded destructors then damaged locations, then take as many # damaged locations as we can fund and build there. funded_locs = damaged_locs[:num_funded_destructors] else: # If we have more funded locations then was actually damaged, then build defences # around damaged locations until we run out of funding. funded_locs = [ damaged_locs[i % len(damaged_locs)] for i in range(num_funded_destructors) ] # Deploy defensive units until we either run out of damaged locations for funded_loc in funded_locs: # Find all possible spawn points in the range of 1 unit around the damaged # unit's location. potential_spawn_locs = state.game_map.get_locations_in_range( funded_loc, 1) for loc in potential_spawn_locs: if state.can_spawn(DESTRUCTOR, loc): state.attempt_spawn(DESTRUCTOR, loc)
def build_template(self, state: gamelib.AdvancedGameState, prev_state): """ Adds any defences to the priority queue if we were destroyed. :param state: game state. :param prev_state: game state. """ if prev_state: self.were_corners_attacked(state, prev_state) if self.R_CORNER_ATTACKED: for i in range(len(self.BASE_TEMPLATE)): if self.BASE_TEMPLATE[i] in self.RIGHT_CORNER_MASK: self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) if self.L_CORNER_ATTACKED: for i in range(len(self.BASE_TEMPLATE)): if self.BASE_TEMPLATE[i] in self.LEFT_CORNER_MASK: self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) for unit in self.BASE_TEMPLATE: if state.get_resource(state.CORES) > self.UNIT_COSTS[unit[1]]: use_destruct = state.get_resource( state.CORES) > self.BUILD_DESTRUCTOR_WALLS_THRESH unit_type = DESTRUCTOR if use_destruct else unit[1] if state.can_spawn(unit_type, unit[0]): state.attempt_spawn(unit_type, unit[0]) low_health_units = self.find_low_health_units( state, self.TEMPLATE_MASK, self.REMOVE_HEALTH_THRESH) self.destroy_low_health_units(state, low_health_units)
def build_defences(self, state: gamelib.AdvancedGameState): # When we're at full build, do nothing! while state.get_resource( state.CORES) > 0 and not self.defences.build_done(): loc, defence_type = self.defences.get_next_defence() if state.can_spawn(defence_type, loc): state.attempt_spawn(defence_type, loc)
def build_template(self, state: gamelib.AdvancedGameState, prev_state): """ Adds any defences to the priority queue if we were destroyed. :param state: game state. :param prev_state: game state. """ if prev_state: self.were_corners_attacked(state, prev_state) debug_write( "Right Corner State: {}".format(self.R_CORNER_ATTACKED), "Left Corner State: {}".format(self.L_CORNER_ATTACKED) ) # # if self.R_CORNER_ATTACKED: # for i in range(len(self.BASE_TEMPLATE)): # if self.BASE_TEMPLATE[i][0] in self.RIGHT_CORNER_MASK: # debug_write("Updating Template ", self.BASE_TEMPLATE[i]) # self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) # # if self.L_CORNER_ATTACKED: # for i in range(len(self.BASE_TEMPLATE)): # if self.BASE_TEMPLATE[i][0] in self.LEFT_CORNER_MASK: # debug_write("Updating Template ", self.BASE_TEMPLATE[i]) # self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) if self.R_CORNER_ATTACKED: for i in range(len(self.BASE_TEMPLATE)): if self.BASE_TEMPLATE[i][0] in self.RIGHT_CORNER_MASK: self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) new_units = [] for loc in self.RIGHT_CORNER_MASK: if loc not in self.TEMPLATE_MASK: new_units.append((loc, DESTRUCTOR)) self.BASE_TEMPLATE = new_units + self.BASE_TEMPLATE if self.L_CORNER_ATTACKED: for i in range(len(self.BASE_TEMPLATE)): if self.BASE_TEMPLATE[i][0] in self.LEFT_CORNER_MASK: self.BASE_TEMPLATE[i] = (self.BASE_TEMPLATE[i][0], DESTRUCTOR) new_units = [] for loc in self.LEFT_CORNER_MASK: if loc not in self.TEMPLATE_MASK: new_units.append((loc, DESTRUCTOR)) self.BASE_TEMPLATE = new_units + self.BASE_TEMPLATE for unit in self.BASE_TEMPLATE: if state.get_resource(state.CORES) > self.UNIT_COSTS[unit[1]]: use_destruct = state.get_resource(state.CORES) > self.BUILD_DESTRUCTOR_WALLS_THRESH unit_type = DESTRUCTOR if use_destruct else unit[1] if state.can_spawn(unit_type, unit[0]): state.attempt_spawn(unit_type, unit[0]) low_health_units = self.find_low_health_units( state, self.TEMPLATE_MASK, self.REMOVE_HEALTH_THRESH) self.destroy_low_health_units(state, low_health_units)
def build_barrel(state: gamelib.AdvancedGameState, left=False): """ Builds the blackbear barrel on the map. :param state: current game state. :param left: """ # Spawn front destructors and encryptors destructors = BARREL_MASK[BARREL_MASK_IDX['destructors'][0]: BARREL_MASK_IDX['destructors'][1]] for i in destructors: if state.can_spawn(DESTRUCTOR, i): state.attempt_spawn(DESTRUCTOR, i) encryptors = BARREL_MASK[ BARREL_MASK_IDX['encryptors'][0]:BARREL_MASK_IDX['encryptors'][1]] for i in encryptors: if state.can_spawn(ENCRYPTOR, i): state.attempt_spawn(ENCRYPTOR, i) end = 12 if state.turn_number > 0 else 19 # open = False # spawn remaining filters for i in range(22, end, -1): # if not state.contains_stationary_unit([i,i-12]) and state.get_resource(state.CORES) < 1: # open = True if state.can_spawn(FILTER, [i, i - 12]): state.attempt_spawn(FILTER, [i, i - 12])
def emp_cheese(current_state: gamelib.AdvancedGameState): bits = current_state.get_resource(current_state.CORES) if bits < 3.0: return None, None global FILTER, ENCRYPTOR, DESTRUCTOR, PING, EMP, SCRAMBLER config = current_state.config FILTER = config["unitInformation"][0]["shorthand"] ENCRYPTOR = config["unitInformation"][1]["shorthand"] DESTRUCTOR = config["unitInformation"][2]["shorthand"] PING = config["unitInformation"][3]["shorthand"] EMP = config["unitInformation"][4]["shorthand"] SCRAMBLER = config["unitInformation"][5]["shorthand"] """ Tries to deploy emp's behind a line of units, while they fire at enemies Idk how many to send yet, but first need to make sure that it will fire at something while being hidden Check our side for rows from either side that we could hide behind For each, make sure we are NOT being hit and that we ARE hitting something Take the row where we hit the most For each of these calculate how much damage we could do with a single emp Place them at the point where we could do the most damage :param current_state: current game state object :param current_coins: current coins tuple (shield_money, attack_money) :return: tuple of (updated current_state object, updated current_coins object) """ m = current_state.game_map # Check top 4 lines check = [] for i in m.get_edge_locations(m.BOTTOM_LEFT)[:-5:-1]: check.append(i) for i in m.get_edge_locations(m.BOTTOM_RIGHT)[:-5:-1]: check.append(i) best = None for i in check: # Can we deploy? if current_state.contains_stationary_unit(i): continue curr = simulate_emp(copy.deepcopy(current_state), i) if best is None or curr > best[0]: best = [curr, i] num = min(int(best[0] / 15) + 1, int(bits / 3)) # I think # current_state.attempt_spawn(EMP, best[1], num) return best, num
def build_template(self, state: gamelib.AdvancedGameState): """ Adds any defences to the priority queue if we were destroyed. :param state: game state. :return: """ for unit in self.BASE_TEMPLATE: if state.get_resource(state.CORES) > self.UNIT_COSTS[unit[1]]: if state.can_spawn(unit[1], unit[0]): state.attempt_spawn(unit[1], unit[0]) low_health_units = self.find_low_health_units( state, self.TEMPLATE_MASK, self.REMOVE_HEALTH_THRESH) self.destroy_low_health_units(state, low_health_units)
def sell_vulnerable_line(state: gamelib.AdvancedGameState): state.warn("DEBUG") danger = [] removed = False for i in range(13,11, -1): for j in range(13-i, i + 15): if state.contains_stationary_unit([j,i]): state.attempt_remove([j,i]) removed = True if removed: break
def offense(self, game_state, turn_state): locations = [[5, 14], [3, 17], [4, 16]] top_left_enemy_destructors = 0 advanced_game_state = AdvancedGameState(self.config, turn_state) for location in locations: top_left_enemy_destructors = max( top_left_enemy_destructors, len(advanced_game_state.get_attackers(location, 1))) top_left_enemy_units = self.get_enemy_left_units(game_state) for _ in range(top_left_enemy_destructors // 3 + top_left_enemy_units // 6): if game_state.can_spawn(EMP, [2, 11]): game_state.attempt_spawn(EMP, [2, 11]) while game_state.can_spawn(PING, [16, 2], 1): game_state.attempt_spawn(PING, [16, 2], 1)
def can_block(self, loc, state: gamelib.AdvancedGameState): target = state.game_map.BOTTOM_LEFT if loc[1] > 13 else state.game_map.BOTTOM_RIGHT path = state.find_path_to_edge(loc, target) for i in path: if i[1] < 17: f = -1 if target == state.game_map.BOTTOM_RIGHT else 1 return [i[0], 13], [i[0] + f, 13] return None, None
def shoot(state: gamelib.AdvancedGameState, left=False): """ Shoots from the blackbeard barrel. :param state: current game state. :param left: :return: """ if state.turn_number == 0: state.attempt_spawn(PING, [13, 0], 2) state.attempt_spawn(PING, [14, 0], 2) # elif open: # state.attempt_spawn(EMP, [17, 3]) elif state.turn_number % 2: bits = state.get_resource(state.BITS) if bits > 4: state.attempt_spawn(PING, [14, 0], 4) state.attempt_spawn(PING, [13, 0], int(state.get_resource(state.BITS)))
def build_passive_defence(state: gamelib.AdvancedGameState): """ Builds out a passive defense. Has 3 hard-coded positions that are best optimized to cover as much of the field as possible on the unprotected side of the barrel of blackbear. :param state: current game state. """ passive_defence_locations = BASE_PASSIVE_LOCS for loc in passive_defence_locations: # First build the Destructor at the proper location. if state.get_resource(state.CORES) > 4: if state.can_spawn(DESTRUCTOR, loc): state.attempt_spawn(DESTRUCTOR, loc) # If we have some more cores left, then build the Filter on top of it. if state.get_resource(state.CORES) > 1: if state.can_spawn(FILTER, loc): state.attempt_spawn(FILTER, [loc[0], loc[1] + 1])
def sawtooth_setup(self, state: gamelib.AdvancedGameState): # Almost symmetrical setup, just need filter on <14, 10> dest_locs = [[2, 11], [6, 11], [11, 11], [16, 11], [21, 11], [25, 11]] filter_locs = [[0, 13], [1, 12], [26, 12], [27, 13]] for dest in destr_locs: if state.can_spawn(DESTRUCTOR, dest): state.attempt_spawn(DESTRUCTOR, dest) for f in filter_locs: if state.can_spawn(FILTER, f): state.attempt_spawn(FILTER, f)
def initial_setup(self, state: gamelib.AdvancedGameState): # Almost symmetrical setup, just need filter on <14, 10> filter_locs = [[0, 13], [1, 12], [2, 11], [3, 11], [4, 11], [6, 10], [8, 11], [21, 10], [23, 11], [24, 11], [25, 11], [26, 12], [27, 13]] destr_locs = [[5, 10], [10, 9], [17, 9], [22, 10]] for dest in destr_locs: if state.can_spawn(DESTRUCTOR, dest): state.attempt_spawn(DESTRUCTOR, dest) for f in filter_locs: if state.can_spawn(FILTER, f): state.attempt_spawn(FILTER, f)
def escort_strategy(self, state: gamelib.AdvancedGameState, defensive_side='left'): # See if we need to use more filters here # This should be dynamic, depending on the board state, kind of like # What stage of the game are we in filter_locs = [[6, 10], [11, 10], [16, 10], [22, 10]] # Spawn 2 EMPs and 2 Scramblers. Again, this should be dynamic emp_locs = [[3, 10], [3, 10]] scrambler_locs = [[4, 9], [4, 9]] for e in emp_locs: if state.can_spawn(EMP, e): state.attempt_spawn(EMP, e) for s in scrambler_locs: if state.can_spawn(SCRAMBLER, s): state.attempt_spawn(SCRAMBLER, s)
def attack_hole(self, state: gamelib.AdvancedGameState, rush_loc, rush_unit): if state.can_spawn(rush_unit, rush_loc): # Find out the proper amount for the amount of bits to spend state.attempt_spawn(rush_unit, rush_loc, state.my_bits())
def blackbeard(self, state: gamelib.AdvancedGameState, left=False): # Do initial first turn setup # Spawn front destructors and encryptors destr = [[23, 13], [24, 13]] encr = [[23, 12], [24, 12], [25, 13], [23, 11]] for i in destr: if state.can_spawn(DESTRUCTOR, i): state.attempt_spawn(DESTRUCTOR, i) for i in encr: if state.can_spawn(ENCRYPTOR, i): state.attempt_spawn(ENCRYPTOR, i) end = 12 if state.turn_number > 0 else 19 # open = False # spawn remaining filters for i in range(22, end, -1): # if not state.contains_stationary_unit([i,i-12]) and state.get_resource(state.CORES) < 1: # open = True if state.can_spawn(FILTER, [i, i - 12]): state.attempt_spawn(FILTER, [i, i - 12]) # if we have extra cores use some of them18,13,9,5 then filters between prio = [[1, 13], [1, 12], [0, 13], [18, 10], [18, 11], [13, 11], [9, 10], [9, 11], [5, 11]] which = [DESTRUCTOR, DESTRUCTOR, FILTER, DESTRUCTOR, FILTER, DESTRUCTOR, DESTRUCTOR, FILTER, DESTRUCTOR] for i in range(len(prio)): if state.get_resource(state.CORES) > 4: if state.can_spawn(which[i], prio[i]): state.attempt_spawn(which[i], prio[i]) i = 0 # Try to spawn some random stuff while i < 10 and state.get_resource(state.CORES) > 6: row = random.randint(10, 11) col = random.randint(13 - row, 19) type = DESTRUCTOR if random.randint(0, 1) else FILTER if state.can_spawn(type, [row, col]): state.attempt_spawn(type, [row, col]) if state.turn_number == 0: state.attempt_spawn(PING, [13, 0], 2) state.attempt_spawn(PING, [14, 0], 2) # elif open: # state.attempt_spawn(EMP, [17, 3]) elif state.turn_number % 2: bits = state.get_resource(state.BITS) if bits > 4: state.attempt_spawn(PING, [14, 0], 4) state.attempt_spawn(PING, [13, 0], int(state.get_resource(state.BITS)))
def attack(self, state: gamelib.AdvancedGameState): emp_loc = [3, 10] while state.can_spawn(EMP, emp_loc, 1): state.attempt_spawn(EMP, emp_loc, 1)
def simulate(self, state: gamelib.AdvancedGameState, unit_type, spawn_loc=(13, 0), num_units=1): map = state.game_map """ TODO: ENCRYPTORS """ target_edge = map.TOP_RIGHT if spawn_loc[0] < 14 else map.TOP_LEFT path = state.find_path_to_edge(spawn_loc, target_edge) total_dmg = 0 total_cores = 0 frames = 2 if unit_type == PING else 4 dmg = 0 if unit_type == SCRAMBLER else (1 if unit_type == PING else 3) for i in range(num_units): map.add_unit(unit_type, spawn_loc) idx = 0 remaining = map[spawn_loc] map.remove_unit(spawn_loc) pings = 0 while idx < len(path): loc = path[idx] for i in remaining: i.x = loc[0] i.y = loc[1] map[loc].append(i) for i in range(frames): defense_dmg = 4 * len(state.get_attackers(loc, 0)) our_dmg = len(map[loc]) * dmg initial = len(map[loc]) if map[loc]: target = state.get_target(map[loc][0]) else: break if target: target.stability -= our_dmg total_dmg += our_dmg total_cores += (our_dmg / target.max_stability) * target.cost if target.stability < 0: map.remove_unit([target.x, target.y]) dead = 0 for i in range(initial): if defense_dmg <= 0 or dead == len(map[loc]): break # Killed one, did they kill more if defense_dmg >= map[loc][dead].stability: defense_dmg -= map[loc][dead].stability dead += 1 # They didn't kill this one else: map[loc][dead].stability -= defense_dmg break # kill the dead ones for i in range(dead): map[loc].pop(0) remaining = map[loc] pings = remaining if len(remaining) == 0: break map.remove_unit(loc) idx += 1 if loc[1] > 14: mod_path = state.find_path_to_edge(spawn_loc, target_edge) if path != mod_path and loc in mod_path: idx = mod_path.index(loc) + 1 path = mod_path return 3.5 * len(pings) + total_cores
def build_passive_blackbeard_defence(state: gamelib.AdvancedGameState): # if we have extra cores use some of them 18,13,9,5 then filters between prio = [[1, 13], [1, 12], [0, 13], [18, 10], [18, 11], [13, 11], [9, 10], [9, 11], [5, 11]] which = [ DESTRUCTOR, DESTRUCTOR, FILTER, DESTRUCTOR, FILTER, DESTRUCTOR, DESTRUCTOR, FILTER, DESTRUCTOR ] for i in range(len(prio)): if state.get_resource(state.CORES) > 4: if state.can_spawn(which[i], prio[i]): state.attempt_spawn(which[i], prio[i]) i = 0 # Try to spawn some random stuff while i < 10 and state.get_resource(state.CORES) > 6: row = random.randint(10, 11) col = random.randint(13 - row, 19) type = DESTRUCTOR if random.randint(0, 1) else FILTER if state.can_spawn(type, [row, col]): state.attempt_spawn(type, [row, col]) if state.turn_number == 0: state.attempt_spawn(PING, [13, 0], 2) state.attempt_spawn(PING, [14, 0], 2) # elif open: # state.attempt_spawn(EMP, [17, 3]) elif state.turn_number % 2: bits = state.get_resource(state.BITS) if bits > 4: state.attempt_spawn(PING, [14, 0], 4) state.attempt_spawn(PING, [13, 0], int(state.get_resource(state.BITS)))