def move(self, me: Player, world: World, game: Game, move: Move): if world.tick_index == 0: move.action = ActionType.CLEAR_AND_SELECT move.right = world.width move.bottom = world.height if world.tick_index == 1: move.action = ActionType.MOVE move.x = world.width / 2.0 move.y = world.height / 2.0
def move(self, me: Player, world: World, game: Game, move: Move): self.map.update(world.new_vehicles, world.vehicle_updates) if world.tick_index == 0: move.action = ActionType.CLEAR_AND_SELECT move.right = world.width move.bottom = world.height if world.tick_index == 1: move.action = ActionType.MOVE move.x = world.width / 1.0 move.y = world.height / 2.0
def do_group(s: MyStrategy, w: World, g: Game, m: Move): m.action = action m.group = gnum if action == ActionType.ASSIGN: s.free_groups.discard(gnum) elif action == ActionType.DISBAND: s.free_groups.add(gnum)
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 select_all(self, move: Move, vehicle_type=None, add_to_selection=False): move.action = ActionType.CLEAR_AND_SELECT if not add_to_selection else ActionType.ADD_TO_SELECTION move.left = 0.0 move.top = 0.0 move.right = self.game.world_width move.bottom = self.game.world_height if vehicle_type is not None: move.vehicle_type = vehicle_type
def do_select(s: MyStrategy, w: World, g: Game, m: Move, a=area): m.action = action #print("Selecting: " + str(a)) m.left = a.left - fuzz m.right = a.right + fuzz m.top = a.top m.bottom = a.bottom m.group = group m.vehicle_type = vtype
def move(self, me: Hockeyist, world: World, game: Game, move: Move): factory = self.create_factory(me, world, game, move) strategy = self.create_strategy(factory, me, world, game, move) move.action = strategy.action move.speed_up = strategy.speed_up move.turn = strategy.turn factory.info[type(strategy)] = strategy.info
def move(self, me: Hockeyist, world: World, game: Game, move: Move): # self.me = me # self.world = world # self.game = game # self.me_move = move if me.state == HockeyistState.SWINGING: move.action = ActionType.STRIKE return if world.puck.owner_player_id == me.player_id: if world.puck.owner_hockeyist_id == me.id: opponent = world.get_opponent_player() net_x = 0.5 * (opponent.net_back + opponent.net_front) net_y = 0.5 * (opponent.net_bottom + opponent.net_top) angle_to_net = me.get_angle_to(net_x, net_y) move.turn = angle_to_net if abs(angle_to_net) < self.STRIKE_ANGLE: move.action = ActionType.STRIKE else: nearest_opponent = self.get_nearest_opponent(me, world) if nearest_opponent is not None: if me.get_distance_to_unit(nearest_opponent) > game.stick_length: move.speed_up = 1 else: move.action = ActionType.STRIKE move.turn = me.get_angle_to_unit(nearest_opponent) else: move.speed_up = 1 move.turn = me.get_angle_to_unit(world.puck) move.action = ActionType.TAKE_PUCK
def move(self, me: Wizard, world: World, game: Game, move: Move): # Every tick, update state first state_machine.update_state(me, world, game) # Take action for this state state_machine.run(me, world, game) # Current state state = state_machine.get_state() # Move move.speed = state.forward_speed move.strafe_speed = state.strafe_speed move.turn = state.turn_angle move.action = state.action
def attack(me: Wizard, game: Game, move: Move, skills: Set, unit: LivingUnit, allow_fireball: bool): action_type, min_cast_distance = MyStrategy.get_action(me, game, skills, unit, allow_fireball) if action_type == ActionType.NONE: return False # We can cast something. is_oriented, cast_angle = MyStrategy.is_oriented_to_unit(me, game, unit) if is_oriented: # Attack! move.cast_angle = cast_angle move.action = action_type move.min_cast_distance = min_cast_distance return True # Turn around to the enemy. move.turn = me.get_angle_to_unit(unit) return True
def read_move(self): if not self.read_boolean(): return None move = Move() move.speed_up = self.read_double() move.turn = self.read_double() move.action = self.read_enum(ActionType) if move.action == ActionType.PASS: move.pass_power = self.read_double() move.pass_angle = self.read_double() elif move.action == ActionType.SUBSTITUTE: move.teammate_index = self.read_int() return move
def moveToNonMedic(self, me: Trooper, world: object, game: Game, move: Move): troopers = world.troopers for trooper in troopers: if trooper.type != TrooperType.FIELD_MEDIC and trooper.teammate: targetX = 0 targetY = 0 move.action = ActionType.MOVE if me.type == TrooperType.FIELD_MEDIC and trooper.hitpoints < trooper.maximal_hitpoints: targetX = trooper.x targetY = trooper.y else: targetX = trooper.x + randint(0, 9) % 3 targetY = trooper.y + randint(0, 9) % 3 self.moveToPoint(targetX, targetY, me, world, game, move)
def shootTrooper(self, trooper : Trooper, move : Move, game : Game, me : Trooper): move.action = ActionType.SHOOT move.x = trooper.x move.y = trooper.y
def move(self, me: Wizard, world: World, game: Game, move: Move): if self.debug: self.debug.syncronize(world) if not self.initialized: self.initialize(me, world, game) self.initialize_tick(me, world, game) score_threshold = -0.1 wizard_score = me.life / (me.max_life * 0.5) - 1 if self.battle_front: self.battle_front.init(world, me) front_score = self.battle_front.get_front_score(me) k = 0.6 common_score = front_score * (1 - k) + wizard_score * k else: common_score = wizard_score nearest_target = Points2D.get_nearest_target(me, world) if nearest_target is not None: distance = me.get_distance_to_unit(nearest_target) angle = me.get_angle_to_unit(nearest_target) if (distance <= game.staff_range) and (abs(angle) < game.staff_sector / 2.0): move.action = ActionType.STAFF elif (distance <= me.cast_range) and (abs(angle) < game.staff_sector / 2.0): move.action = ActionType.MAGIC_MISSILE move.cast_angle = angle move.min_cast_distance = distance - nearest_target.radius + game.magic_missile_radius if common_score < score_threshold: previous_waypoint = Points2D.get_previous_waypoint( self.waypoints, me) self.map.note_enemy_angle = False self.go_to(move, previous_waypoint, note_angle=False) self.last_actions[world.tick_index % STOP_CHECK_TICK_COUNT] = Action.BACK return else: nearest_target = Points2D.get_nearest_target(me, world) if nearest_target is not None: distance = me.get_distance_to_unit(nearest_target) angle = me.get_angle_to_unit(nearest_target) if distance <= me.cast_range: self.go_to(move, None, note_angle=False) if abs(angle) < game.staff_sector / 2.0: move.action = ActionType.MAGIC_MISSILE move.cast_angle = angle move.min_cast_distance = distance - nearest_target.radius + game.magic_missile_radius self.last_actions[world.tick_index % STOP_CHECK_TICK_COUNT] = Action.ENEMY return else: min_attack_dist = min_atack_distance(me) * self.life_coef new_x = me.x + (nearest_target.x - me.x) / distance * ( distance - min_attack_dist) new_y = me.y + (nearest_target.y - me.y) / distance * ( distance - min_attack_dist) self.go_to(move, Point2D(new_x, new_y), note_angle=True) self.last_actions[world.tick_index % STOP_CHECK_TICK_COUNT] = Action.NEXT return else: next_waypoint = Points2D.get_next_waypoint(self.waypoints, me) note_angle = True if world.tick_index > STOP_CHECK_TICK_COUNT: last_pos_index = (world.tick_index + 1) % STOP_CHECK_TICK_COUNT dist_last_poses = me.get_distance_to_unit( self.last_poses[last_pos_index]) # если далеко не ушел и если последние все действия NEXT if ((dist_last_poses < STOP_CHECK_TICK_COUNT * 0.2 * game.wizard_forward_speed) and (sum([x == Action.NEXT for x in self.last_actions]) == STOP_CHECK_TICK_COUNT)): note_angle = False self.map.neutral_coef = 1000 * np.random.normal(1, 0.3) self.map.neutral_dist_coef = 1000 self.go_to(move, next_waypoint, note_angle=note_angle) self.last_actions[world.tick_index % STOP_CHECK_TICK_COUNT] = Action.NEXT if world.tick_index < SLOW_MOVE_TICK_COUNT: move.speed *= 0.5 move.strafe_speed *= 0.5 return
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
def heal(self, trooper : Trooper, move : Move): move.action = ActionType.HEAL move.x = trooper.x move.y = trooper.y print('Солдат полечил')
def do_scale(s: MyStrategy, w: World, g: Game, m: Move): m.action = ActionType.SCALE m.factor = factor m.x = center.x m.y = center.y
def throwGrenade(self, trooper : Trooper, move : Move): move.action = ActionType.THROW_GRENADE move.x = trooper.x move.y = trooper.y
def move(self, me: Wizard, world: World, game: Game, move: Move): move.speed = game.wizard_forward_speed move.strafe_speed = game.wizard_strafe_speed move.turn = game.wizard_max_turn_angle move.action = ActionType.MAGIC_MISSILE
def do_rotate(s: MyStrategy, w: World, g: Game, m: Move): m.action = ActionType.ROTATE m.angle = angle m.max_angular_speed = max_speed m.x = center.x m.y = center.y
def moveToPoint(self, targetX, targetY, me: Trooper, world: object, game: Game, move: Move): cells = world.cells offsetX = 0 if me.x > targetX: offsetX = -1 elif me.x < targetX: offsetX = 1 else: offsetX = 0 offsetY = 0 if me.y > targetY: offsetY = -1 elif me.y < targetY: offsetY = 1 else: offsetY = 0 x = -1 y = -1 canMoveToPoint = False if offsetX != 0: x = me.x + offsetX y = me.y elif offsetY != 0: x = me.x y = me.y + offsetY for bonus in world.bonuses: if bonus.x == x and bonus.y == y: canMoveToPoint = True canMoveX = offsetX != 0 and cells[me.x + offsetX][me.y] == CellType.FREE canMoveY = offsetY != 0 and cells[me.x][me.y + offsetY] == CellType.FREE canMoveX = canMoveX or canMoveToPoint canMoveY = canMoveY or canMoveToPoint if canMoveX or canMoveY: move.action = ActionType.MOVE if canMoveX and canMoveY: if randint(0, 9) % 2 == 0: move.x = me.x + offsetX move.y = me.y else: move.x = me.x move.y = me.y + offsetY elif canMoveX: move.x = me.x + offsetX move.y = me.y else: move.x = me.x move.y = me.y + offsetY else: print('Recalculate direction') quarter = 0 if me.x > targetX and me.y < targetY: quarter = 1 elif me.x > targetX and me.y > targetY: quarter = 2 elif me.x < targetX and me.y > targetY: quarter = 3 elif me.x < targetX and me.y < targetY: quarter = 4 if quarter == 1: offsetX = 1 offsetY = -1 elif quarter == 2: offsetX = 1 offsetY = 1 elif quarter == 3: offsetX = -1 offsetY = 1 elif quarter == 4: offsetX = -1 offsetY = -1 if offsetX != 0: x = me.x + offsetX y = me.y elif offsetY != 0: x = me.x y = me.y + offsetY canMoveX = offsetX != 0 and cells[me.x + offsetX][me.y] == CellType.FREE canMoveY = offsetY != 0 and cells[me.x][me.y + offsetY] == CellType.FREE #if not canMoveX and not canMoveY: #self.moveToPoint(targetX + randint(0, 9) % 2, targetY + randint(0, 9) % 2, me, world, game, move) #return if canMoveX or canMoveY: print('Can move new direction') move.action = ActionType.MOVE if canMoveX and canMoveY: if randint(0, 9) % 2 == 0: move.x = me.x + offsetX move.y = me.y else: move.x = me.x move.y = me.y + offsetY elif canMoveX: move.x = me.x + offsetX move.y = me.y else: move.x = me.x move.y = me.y + offsetY
def shrink_selected(self, move: Move): move.x, move.y = self.my_x, self.my_y move.action = ActionType.SCALE move.factor = 0.1
def rotate_selected(self, move: Move): move.x, move.y = self.my_x, self.my_y move.action = ActionType.ROTATE move.angle = self.rotate_angle
def move(self, me: Hockeyist, world: World, game: Game, move: Move): move.speed_up = -1.0 move.turn = pi move.action = ActionType.STRIKE
def decreaseStance(self, move : Move, game : Game, me : Trooper): move.action = ActionType.LOWER_STANCE move.direction = Direction.CURRENT_POINT
def do_move(s: MyStrategy, w: World, g: Game, m: Move): m.action = ActionType.MOVE m.x = destination.x m.y = destination.y #print("Moving to: " + str(destination.x) + ":" + str(destination.y)) m.max_speed = max_speed
def expand(self, move: Move, x: float, y: float): move.action = ActionType.SCALE move.x = x move.y = y move.factor = 1.5
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 move(self, me: Wizard, world: World, game: Game, move: Move): self.log('TICK %s' % world.tick_index) self._init(game, me, world, move) self.log('me %s %s %f' % (me.x, me.y, me.get_distance_to(*self.INIT_POINT))) # initial cooldown if self.PASS_TICK_COUNT: self.PASS_TICK_COUNT -= 1 self.log('initial cooldown pass turn') return # select lane self._select_lane(me) # STRATEGY LOGIC enemy_targets = self._enemies_in_attack_distance(me) enemy_who_can_attack_me = self._enemies_who_can_attack_me(me) retreat_move_lock = False retreat_by_low_hp = False # чистим уже погибшие снаряды из карты current_projectiles_id = set( [p.id for p in self.W.projectiles if p.owner_unit_id == me.id]) cached_projectiles_id = set(self.PROJECTILE_MAP.keys()) for k in cached_projectiles_id - current_projectiles_id: del self.PROJECTILE_MAP[k] # ищем последний созданный снаряд и его цель для карты снарядов if self.PROJECTILE_LAST_ENEMY: for p in self.W.projectiles: if p.owner_unit_id == me.id and p.id not in self.PROJECTILE_MAP: self.PROJECTILE_MAP[p.id] = self.PROJECTILE_LAST_ENEMY self.PROJECTILE_LAST_ENEMY = None break self.log('projectile map %s' % str(self.PROJECTILE_MAP)) # если ХП мало отступаем if me.life < me.max_life * self.LOW_HP_FACTOR: retreat_by_low_hp = True self.log('retreat by low HP') if len(enemy_who_can_attack_me): self._goto_backward(me) retreat_move_lock = True if len(enemy_who_can_attack_me) > self.MAX_ENEMIES_IN_DANGER_ZONE: self.log('retreat by enemies in danger zone') self._goto_backward(me) retreat_move_lock = True # если врагов в радиусе обстрела нет - идём к их базе если не находимся в режиме отступления if not enemy_targets and not retreat_by_low_hp: self.log('move to next waypoint') self._goto_forward(me) # если на поле есть наши снаряды и расстояние до цели меньше расстояния каста # пробуем подойти к цели (если не находимся в отступлении) if not retreat_by_low_hp: potential_miss_enemies = self._find_potential_miss_enemy(me) self.log('found %s potential miss enemies' % potential_miss_enemies) if potential_miss_enemies: e = self._sort_by_angle(me, potential_miss_enemies)[0] self._goto_enemy(me, e) if enemy_targets: # есть враги в радиусе обстрела self.log('found %d enemies for attack' % len(enemy_targets)) selected_enemy = self._select_enemy_for_attack(me, enemy_targets) angle_to_enemy = me.get_angle_to_unit(selected_enemy) # если цель не в секторе атаки - поворачиваемся к ней (приоритет за направлением на точку отступления) if not self._enemy_in_attack_sector(me, selected_enemy): if not retreat_move_lock: self.log('select enemy for turn %s' % selected_enemy.id) self.MOVE_TURN = angle_to_enemy else: self.log('ignore select enemy for turn %s by retreat' % selected_enemy.id) else: # если можем атаковать - атакуем self.log('select enemy for attack %s' % selected_enemy.id) move.cast_angle = angle_to_enemy if self._enemy_in_cast_distance(me, selected_enemy): self.log('cast attack') move.action = ActionType.MAGIC_MISSILE move.min_cast_distance = self._cast_distance( me, selected_enemy) self.PROJECTILE_LAST_ENEMY = selected_enemy.id else: self.log('staff attack') move.action = ActionType.STAFF if self.MOVE_TURN is not None: move.turn = self.MOVE_TURN self.MOVE_TURN = None if self.MOVE_SPEED is not None: move.speed = self.MOVE_SPEED self.MOVE_SPEED = None if self.MOVE_STRAFE_SPEED is not None: move.strafe_speed = self.MOVE_STRAFE_SPEED self.MOVE_STRAFE_SPEED = None