def new_move(self, action=None, group=0, x_range=(0.0, WORLD_WIDTH), y_range=(0.0, WORLD_HEIGHT), vector=(0.0, 0.0), angle=0.0, factor=0.0, max_speed=0.0, max_angular_speed=0.0, vehicle_type=None, facility_id=-1, vehicle_id=-1): m = Move() m.action = action m.group = group m.left, m.right = x_range m.top, m.bottom = y_range m.x, m.y = vector m.angle = angle m.factor = factor m.max_speed = max_speed m.max_angular_speed = max_angular_speed m.vehicle_type = vehicle_type m.facility_id = facility_id m.vehicle_id = vehicle_id return m
def move_forward(self, move: Move): enemy_vehicle = min( (vehicle for vehicle in self.enemy_vehicles.values()), key=(lambda vehicle: vehicle.get_distance_to(self.my_x, self.my_y)), ) x, y = enemy_vehicle.x, enemy_vehicle.y # Nuclear strike logic. if ( self.me.remaining_nuclear_strike_cooldown_ticks == 0 and enemy_vehicle.get_distance_to(self.my_x, self.my_y) > self.r ): vehicle, distance = min( self.get_vehicles_with_distance_to(self.my_vehicles.values(), enemy_vehicle), key=itemgetter(1), ) if distance < self.get_vision_range(vehicle): print('[{}] TACTICAL NUCLEAR STRIKE!'.format(self.world.tick_index)) move.action = ActionType.TACTICAL_NUCLEAR_STRIKE move.vehicle_id = vehicle.id move.x = enemy_vehicle.x move.y = enemy_vehicle.y return move.action = ActionType.MOVE move.max_speed = self.get_max_speed() if self.me.score > self.world.get_opponent_player().score: # We're winning. Why take a risk? Slowly go away. move.x = -(x - self.my_x) move.y = -(y - self.my_y) move.max_speed = 0.01 elif ( self.attack_ratio >= 1.0 or enemy_vehicle.get_distance_to(self.my_x, self.my_y) > self.r + 20.0 or self.world.tick_index > 19000 ): # We have enough vehicles or opponent is too far away, let's attack! move.x = x - self.my_x move.y = y - self.my_y else: # We're losing the battle. Let's move left-right until something good happens. move.x = y - self.my_y move.y = -(x - self.my_x) if getrandbits(1): move.x = -move.x move.y = -move.y
def move(self, me: Player, world: World, game: Game, move: Move): self.update(me, world, game) self.clear_cache() # PREPROCESSING OF MEDIANS # me median_me_all = self.get_median(me) median_me_ground = self.get_median(me, types=[0, 3, 4]) median_me_aerial = self.get_median(me, types=[1, 2]) median_me_of_type = [self.get_median(me, types=[type]) for type in range(5)] # enemy median_en_all = self.get_median(self.enemy) # median_en_ground = self.get_median(self.enemy, types=[0, 3, 4]) # median_en_aerial = self.get_median(self.enemy, types=[1, 2]) # median_en_of_type = [self.get_median(self.enemy, types=[type]) # for type in range(5)] if world.tick_index % 100 == 0: print("NOW AT TICK", world.tick_index) print(median_me_all) print("CENTERS:") for type in range(5): median = median_me_of_type[type] print(" ", self.VEHICLE_TYPE_NAMES[type], median) X = np.array(list(self.get_data_of_units(me, types=[type])[0])) Y = np.array(list(self.get_data_of_units(me, types=[type])[1])) print(" ", " ", "domain:", X.min(), X.max()) print(" ", " ", "range:", Y.min(), Y.max()) print() # INIT INFO if world.tick_index == 0: fighter_x, fighter_y = median_me_of_type[1] helicopter_x, helicopter_y = median_me_of_type[2] if (fighter_x == helicopter_x and fighter_y < helicopter_y) or \ (fighter_x > fighter_y and not (fighter_x < helicopter_x and fighter_y == helicopter_y)): self.aerial_formation_type = 'right_down' else: self.aerial_formation_type = 'down_right' self.next_formation_stage(stage='aerial') self.next_formation_stage(stage='ground') # PLANNED TACTICS FOR ROUND II # 1) do phase 1 improved using potential flows # 2) split into 4, treat these groups as single entities # 3) use potential flows to occupy facilities # 4) produce enough units for a 5th group # 5) if one facility is not occupied, then use the 5th group to occupy it # else 2 or more groups to invade an facility and let the 5th remain on it # PHASE I: FORMATION ## AERIAL UNITS if self.aerial_formation_stage == 1 and self.lock == 'free': # select fighter planes self.act_new_select(move, vehicle_type=1, stage='aerial') self.lock = 'aerial' return elif self.aerial_formation_stage == 2 and self.lock == 'aerial': # move fighter planes if self.aerial_formation_type == 'right_down': self.act_move(move, source=median_me_of_type[1], dest=(270, median_me_of_type[1][1]), stage='aerial') else: self.act_move(move, source=median_me_of_type[1], dest=(median_me_of_type[1][0], 270), stage='aerial') self.aerial_wait = self.DEF_AERIAL_WAIT self.lock = 'free' return elif self.aerial_formation_stage == 3: # wait for fighter planes to be in position fighter_x, fighter_y = median_me_of_type[1] if self.aerial_formation_type == 'right_down': if abs(fighter_x - 270) < self.EPS: if self.aerial_wait == 0: self.next_formation_stage(stage='aerial') else: self.aerial_wait -= 1 else: if abs(fighter_y - 270) < self.EPS: if self.aerial_wait == 0: self.next_formation_stage(stage='aerial') else: self.aerial_wait -= 1 elif self.aerial_formation_stage == 4 and self.lock == 'free': # select fighter planes self.act_new_select(move, vehicle_type=1, stage='aerial') self.lock = 'aerial' return elif self.aerial_formation_stage == 5 and self.lock == 'aerial': # move fighter planes if self.aerial_formation_type == 'right_down': self.act_move(move, source=median_me_of_type[1], dest=(median_me_of_type[1][0], 270), stage='aerial') else: self.act_move(move, source=median_me_of_type[1], dest=(270, median_me_of_type[1][1]), stage='aerial') self.lock = 'free' return elif self.aerial_formation_stage == 6 and self.lock == 'free': # select helicopters self.act_new_select(move, vehicle_type=2, stage='aerial') self.lock = 'aerial' return elif self.aerial_formation_stage == 7 and self.lock == 'aerial': # move helicopters if self.aerial_formation_type == 'right_down': dest = (274 - self.AERIAL_SQUAD_SIZE - 20, 274) else: dest = (274, 274 - self.AERIAL_SQUAD_SIZE - 20) self.act_move(move, source=median_me_of_type[2], dest=dest, stage='aerial') self.aerial_wait = self.DEF_AERIAL_WAIT self.lock = 'free' return elif self.aerial_formation_stage == 8: # wait for both to be in position if not self.check_in_pos(median_me_of_type[1], (270, 270)): pass elif (self.aerial_formation_type == 'right_down' and self.check_in_pos(median_me_of_type[2], (274 - self.AERIAL_SQUAD_SIZE - 20, 274))) or \ (self.aerial_formation_type == 'down_right' and self.check_in_pos(median_me_of_type[2], (274, 274 - self.AERIAL_SQUAD_SIZE - 20))): if self.aerial_wait == 0: self.next_formation_stage(stage='aerial') else: self.aerial_wait -= 1 elif self.aerial_formation_stage == 9 and self.lock == 'free': # select fighter planes self.act_new_select(move, vehicle_type=1, stage='aerial') self.lock = 'aerial' return elif self.aerial_formation_stage == 10 and self.lock == 'aerial': # scale fighter planes self.act_scale(move, median_me_of_type[1], stage='aerial') self.lock = 'free' return elif self.aerial_formation_stage == 11 and self.lock == 'free': # select helicopters self.act_new_select(move, vehicle_type=2, stage='aerial') self.lock = 'aerial' return elif self.aerial_formation_stage == 12 and self.lock == 'aerial': # scale helicopters self.act_scale(move, median_me_of_type[2], stage='aerial') self.aerial_wait = self.DEF_AERIAL_WAIT return elif self.aerial_formation_stage == 13: # wait for both to scale if self.check_if_scaled(vehicle_type=1, target_size=self.AERIAL_SQUAD_SIZE) and \ self.check_if_scaled(vehicle_type=2, target_size=self.AERIAL_SQUAD_SIZE): if self.aerial_wait == 0: self.next_formation_stage(stage='aerial') else: self.aerial_wait -= 1 elif self.aerial_formation_stage == 14 and self.lock == 'aerial': # finish formation self.act_move(move, source=median_me_of_type[2], dest=(274, 274), stage='aerial') self.aerial_wait = self.DEF_AERIAL_WAIT return elif self.aerial_formation_stage == 15: # wait for helicopters to be in position if self.check_in_pos(median_me_of_type[2], (274, 274)): if self.aerial_wait == 0: self.next_formation_stage(stage='aerial') else: self.aerial_wait -= 1 elif self.aerial_formation_stage == 16 and self.lock == 'aerial': # add fighters to selection self.act_add_select(move, vehicle_type=1, stage='aerial') return elif self.aerial_formation_stage == 17 and self.lock == 'aerial': # move to centroid of ground units self.act_move(move, source=median_me_of_type[2], dest=self.get_centroid(self.me, types=[0, 3, 4]), stage='aerial') self.lock = 'free' return ## GROUND UNITS '''move_to = {45:56.7, 119:178.3, 193:299.9} if self.ground_formation_stage in [1, 2, 3, 4, 5, 6]: i = (self.ground_formation_stage-1)//2 vehicle_type = [0, 3, 4][i] if self.ground_formation_stage % 2 == 1 and self.lock == 'free': self.act_new_select(move, vehicle_type, stage='ground') self.lock = 'ground' elif self.lock == 'ground': med = median_me_of_type[vehicle_type] self.act_move(move, source=med, dest=(move_to[int(med[0])]+4.1*i, move_to[int(med[1])]+4.1*i), stage='ground') self.lock = 'free' return elif world.tick_index > 400 and self.ground_formation_stage in [7, 8, 9, 10, 11, 12]: i = (self.ground_formation_stage-7)//2 vehicle_type = [0, 3, 4][i] if self.ground_formation_stage % 2 == 1 and self.lock == 'free': self.act_new_select(move, vehicle_type, stage='ground') self.lock = 'ground' elif self.lock == 'ground': med = median_me_of_type[vehicle_type] self.act_scale(move, pivot=med, factor=self.GROUND_SCALE_FACTOR, stage='ground') self.lock = 'free' return elif world.tick_index > 700 and self.ground_formation_stage in [13, 14, 15, 16, 17, 18]: i = (self.ground_formation_stage-13)//2 vehicle_type = [0, 3, 4][i] if self.ground_formation_stage % 2 == 1 and self.lock == 'free': self.act_new_select(move, vehicle_type, stage='ground') self.lock = 'ground' elif self.lock == 'ground': med = median_me_of_type[vehicle_type] self.act_move(move, relative=(median_me_ground[0]-med[0], 0), stage='ground') self.lock = 'free' ''' if self.ground_formation_stage == 1 and self.lock == 'free': # select ARRVs self.act_new_select(move, vehicle_type=0, stage='ground') self.lock = 'ground' return elif self.ground_formation_stage == 2 and self.lock == 'ground': # add IFVs to selection self.act_add_select(move, vehicle_type=3, stage='ground') return elif self.ground_formation_stage == 3 and self.lock == 'ground': # add Tanks to selection self.act_add_select(move, vehicle_type=4, stage='ground') return elif self.ground_formation_stage == 4 and self.lock == 'ground': # rotate all ground units self.act_rotate(move, types=[0, 3, 4], pivot=(122, 122), stage='ground') self.form_rotation_start = world.tick_index self.lock = 'free' return ## MOVE IN elif self.ground_formation_stage == 5: # wait for 300 ticks if world.tick_index - self.form_rotation_start >= 300: self.next_formation_stage(stage='ground') elif self.ground_formation_stage in [6, 7, 8, 9, 10, 11]: # move each type of vehicle to the center ground_centroid = self.get_centroid(self.me, types=[0, 3, 4]) type = [0, 3, 4][(self.ground_formation_stage-6)//2] type_centroid = self.get_centroid(self.me, types=[type]) if self.get_squared_distance(*ground_centroid, *type_centroid) < self.EPS: pass if self.ground_formation_stage % 2 == 0 and self.lock == 'free': self.act_new_select(move, vehicle_type=type, stage='ground') self.lock = 'ground' elif self.lock == 'ground': self.act_move(move, source=type_centroid, dest=(122, 122), stage='ground') self.lock = 'free' return elif self.ground_formation_stage == 12: # wait for another 300 ticks if world.tick_index - self.form_rotation_start >= 600: self.next_formation_stage(stage='ground') elif self.ground_formation_stage == 13 and self.lock == 'free': # select ARRVs self.act_new_select(move, vehicle_type=0, stage='ground') self.lock = 'ground' return elif self.ground_formation_stage == 14 and self.lock == 'ground': # add IFVs to selection self.act_add_select(move, vehicle_type=3, stage='ground') return elif self.ground_formation_stage == 15 and self.lock == 'ground': # add Tanks to selection self.act_add_select(move, vehicle_type=4, stage='ground') return elif self.ground_formation_stage == 16 and self.lock == 'ground': # scale down the formation of ground units self.act_scale(move, self.get_centroid(self.me, types=[0, 3, 4]), factor=0.1, stage='ground') self.lock = 'free' return # DETECT ENEMY NUKES # NOTE: only does this after the formation if self.enemy_is_nuking == False and self.enemy.next_nuclear_strike_tick_index > 0: self.enemy_is_nuking = True self.en_nuke_detected = world.tick_index self.en_nuke_x = self.enemy.next_nuclear_strike_x self.en_nuke_y = self.enemy.next_nuclear_strike_y self.en_nuke_tick = self.enemy.next_nuclear_strike_tick_index elif self.enemy_is_nuking == True and self.enemy.next_nuclear_strike_tick_index < 0: self.enemy_is_nuking = False self.en_nuke_detected = -1 # EVADE ENEMY NUKES if self.enemy_is_nuking == True: # OPTION: delay scale up when enemy is nuking to prevent the # units from deviating too much from the formation if world.tick_index == self.en_nuke_detected: self.act_new_select(move) elif world.tick_index == self.en_nuke_detected + 1: self.act_scale(move, pivot=(self.en_nuke_x, self.en_nuke_y), factor=10.0) # do nothing while enemy is nuking return # REGROUP if self.enemy_is_nuking == False and world.tick_index <= self.en_nuke_tick + 32: if world.tick_index == self.en_nuke_tick + 1: self.act_new_select(move) elif world.tick_index == self.en_nuke_tick + 2: self.act_scale(move, pivot=(self.en_nuke_x, self.en_nuke_y), factor=0.1) # do nothing else while regrouping return # PHASE II: TRAVEL ACROSS GAME WORLD # OPTION: use potential fields to calculate movement patterns for idx in range(1000, 20001, 250): if world.tick_index == idx + 1: self.act_new_select(move) elif world.tick_index == idx + 2: me_x, me_y = median_me_all en_x, en_y = self.world.width, self.world.height for centroid in self.get_centroids(self.enemy, method='kmeans'): if self.get_squared_distance(me_x, me_y, *centroid) < \ self.get_squared_distance(me_x, me_y, en_x, en_y): en_x, en_y = centroid self.act_move(move, source=(me_x, me_y), dest=(en_x, en_y), max_speed=game.tank_speed * game.swamp_terrain_speed_factor) # REFORM # Overrides previous loop for idx in range(1500, 20001, 1500): if world.tick_index == idx + 1: self.act_new_select(move, vehicle_type=1) elif world.tick_index == idx + 2: self.act_add_select(move, vehicle_type=2) elif world.tick_index == idx + 3: self.act_move(move, source=median_me_aerial, dest=median_me_ground) elif world.tick_index == idx + 4: self.act_new_select(move, vehicle_type=0) elif world.tick_index == idx + 5: self.act_add_select(move, vehicle_type=3) elif world.tick_index == idx + 6: self.act_add_select(move, vehicle_type=4) elif world.tick_index == idx + 7: self.act_rotate(move, types=[0, 3, 4], angle=np.pi/2) if world.tick_index == 250 + idx + 1: self.act_new_select(move) elif world.tick_index == 250 + idx + 2: self.act_scale(move, pivot=median_me_all, factor=0.1) # NUCLEAR OPTION (not really an option; all hail america!) # Only done when the strategy is idle if world.tick_index % 10 == 0 and self.can_nuke() and move.action is None: best_nuke_score = 0 # TODO: Take the velocity of the target into account # TODO: Take your velocity into account for planning when to nuke for centroid in self.get_centroids(self.enemy, method='kmeans'): unit_nuking = self.get_nuking_unit(*centroid) damages = self.calc_nuke_damages(*centroid) if unit_nuking == -1 or damages[1] < self.EPS: continue if damages[0]/damages[1] <= self.SIG_NUKE_DAMAGE_RATIO \ and damages[1] - damages[0] > best_nuke_score: move.action = ActionType.TACTICAL_NUCLEAR_STRIKE move.x, move.y = centroid move.vehicle_id = unit_nuking break if move.action == ActionType.TACTICAL_NUCLEAR_STRIKE: print("NUKE: ({}, {}) with unit #{}".format(move.x, move.y, move.vehicle_id))
def do_nuke(s: MyStrategy, w: World, g: Game, m: Move): m.action = ActionType.TACTICAL_NUCLEAR_STRIKE m.x = target.x m.y = target.y m.vehicle_id = navigator