def interweave(self, packet, drones, start_time) -> StepResult: """ Make bots jump alternating such that they jump over each other. """ elapsed = packet.game_info.seconds_elapsed - start_time start = 0 hold = 0.135 buffer = 0.53 car_states = {} for drone in drones: # Speed controller vel = np.linalg.norm(drone.vel * np.array([1, 1, 0])) drone.ctrl.throttle = 0 if vel > 850 else 1 # jump controller if (drone.index % 2 == 0): if start < elapsed < start + hold: drone.ctrl.jump = True elif start + 2 * buffer < elapsed < start + 2 * buffer + hold: drone.ctrl.jump = True elif start + 4 * buffer < elapsed < start + 4 * buffer + hold: drone.ctrl.jump = True elif start + 6 * buffer < elapsed < start + 6 * buffer + hold: drone.ctrl.jump = True else: if start + buffer < elapsed < start + buffer + hold: drone.ctrl.jump = True elif start + 3 * buffer < elapsed < start + 3 * buffer + hold: drone.ctrl.jump = True elif start + 5 * buffer < elapsed < start + 5 * buffer + hold: drone.ctrl.jump = True self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=elapsed > start + 8 * buffer)
def circular_procession(self, packet: GameTickPacket, drones, start_time) -> StepResult: self.ball.update(packet) elapsed = packet.game_info.seconds_elapsed - start_time inactive_drones = max((elapsed - 4) / 0.48, 0) radian_spacing = 2 * math.pi / max(60 - inactive_drones, 16) adjusted_radius = radius - elapsed * 75 for i, drone in enumerate(drones): if i >= inactive_drones: if i < 60: progress = i * radian_spacing + elapsed * .25 target = [ adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), 0 ] slow_to_pos(drone, target) continue if len(self.drone_aerials) == i: progress = i * radian_spacing + (elapsed + 2) * .25 target = Vector(adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), 200 + i * 10) self.drone_aerials.append(Hover(target, i != 60)) self.drone_aerials[i].target.z += 0.1 self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed) if i == 60: break return StepResult(finished=inactive_drones > 61)
def make_squares(self, packet, drones, start_time) -> StepResult: """ Separates all the bots into two squares, facing each other. """ self.squareA = drones[:32] self.squareB = drones[32:] spacing = 250 y_offset = 3500 x_offset = 7 * spacing / 2 car_states = {} for i, drone in enumerate(self.squareA): car_states[drone.index] = CarState( Physics(location=Vector3(x_offset - spacing * (i % 8), -y_offset - spacing * (i // 8), 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, np.pi / 2, 0))) for i, drone in enumerate(self.squareB): car_states[drone.index] = CarState( Physics(location=Vector3(-x_offset + spacing * (i % 8), y_offset + spacing * (i // 8), 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, -np.pi / 2, 0))) self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=True)
def interweave(self, packet, drones, start_time) -> StepResult: """ Make bots jump alternating such that they jump over each other. """ elapsed = packet.game_info.seconds_elapsed - start_time start = 0.0 hold = 0.05 buffer = 0.65 for drone in drones: drone.ctrl = SimpleControllerState() # Speed controller. vel = np.linalg.norm(drone.vel * np.array([1, 1, 0])) drone.ctrl.throttle = 0 if vel > 650 else 0.7 if (drone.index % 2 == 0): if start < elapsed < start + hold: drone.ctrl.jump = True elif start + 2 * buffer < elapsed < start + 2 * buffer + hold: drone.ctrl.jump = True elif start + 4 * buffer < elapsed < start + 4 * buffer + hold: drone.ctrl.jump = True elif start + 6 * buffer < elapsed < start + 6 * buffer + hold: drone.ctrl.jump = True else: if start + buffer < elapsed < start + buffer + hold: drone.ctrl.jump = True elif start + 3 * buffer < elapsed < start + 3 * buffer + hold: drone.ctrl.jump = True elif start + 5 * buffer < elapsed < start + 5 * buffer + hold: drone.ctrl.jump = True return StepResult(finished=elapsed > start + 8 * buffer)
def hide_ball(self, packet, drones, start_time) -> StepResult: """ Places the ball above the roof of the arena to keep it out of the way. """ self.game_interface.set_game_state(GameState(ball=BallState(physics=Physics( location=Vector3(0, 0, 3000), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0))))) return StepResult(finished=True)
def drift_downward(self, packet, drone, start_time) -> StepResult: """ Causes cars to boost and pitch until they land on their wheels. This is tuned to work well when place_near_ceiling has just been called. """ drone.ctrl = SimpleControllerState(boost=drone.vel[2] < -280, throttle=1, pitch=-0.15) wheel_contact = packet.game_cars[drone.index].has_wheel_contact return StepResult(finished=wheel_contact)
def torus_flight_pattern(self, packet, drones: List[Drone], start_time) -> StepResult: # self.renderer.begin_rendering(drones[0].index) radian_spacing = 2 * math.pi / len(drones) if len(self.aerials) == 0: for index, drone in enumerate(drones): self.aerials.append( Aerial(self.game_info.cars[drone.index], vec3(0, 0, 0), 0)) self.angular_progress.append(index * radian_spacing) elapsed = packet.game_info.seconds_elapsed - start_time # radius = 4000 - elapsed * 100 if self.previous_seconds_elapsed == 0: time_delta = 0 else: time_delta = packet.game_info.seconds_elapsed - self.previous_seconds_elapsed radius = 900 * (1 + math.cos(elapsed * TORUS_RATE)) + 300 height = 450 * (1 + math.sin(elapsed * TORUS_RATE)) + 800 # self.renderer.draw_string_2d(10, 10, 2, 2, f"r {radius}", self.renderer.white()) # self.renderer.draw_string_2d(10, 30, 2, 2, f"z {drones[0].pos[2]}", self.renderer.white()) for index, drone in enumerate(drones): if "sniped" in drone.attributes: continue # This function was fit from the following data points, where I experimentally found deltas which # worked well with sampled radius values. # {2500, 0.7}, {1000, 0.9}, {500, 1.2}, {200, 2.0} # Originally was 2476 / (radius + 1038) # angular_delta = time_delta * (800 / radius + 0.2) angular_delta = time_delta * RADIUS_SPEED.lerp(radius) self.angular_progress[index] += angular_delta aerial = self.aerials[index] progress = self.angular_progress[index] target = Vec3(radius * math.sin(progress), radius * math.cos(progress), height) to_target = target - Vec3(drone.pos[0], drone.pos[1], drone.pos[2]) # self.renderer.draw_line_3d(drone.pos, target, self.renderer.yellow()) aerial.target = vec3(target.x, target.y, target.z) aerial.t_arrival = drone.time + to_target.length() / 2000 + 0.3 aerial.step(0.008) drone.ctrl.boost = aerial.controls.boost drone.ctrl.pitch = aerial.controls.pitch drone.ctrl.yaw = aerial.controls.yaw drone.ctrl.roll = aerial.controls.roll drone.ctrl.jump = aerial.controls.jump self.previous_seconds_elapsed = packet.game_info.seconds_elapsed # self.renderer.end_rendering() return StepResult(finished=elapsed > 160)
def wave_jump(self, packet, drone, start_time) -> StepResult: """ Makes all cars jump in sequence, "doing the wave" if they happen to be lined up. https://gfycat.com/remorsefulsillyichthyosaurs """ elapsed = packet.game_info.seconds_elapsed - start_time jump_start = drone.index * 0.06 jump_end = jump_start + .5 drone.ctrl = SimpleControllerState( jump=jump_start < elapsed < jump_end) wheel_contact = packet.game_cars[drone.index].has_wheel_contact return StepResult(finished=elapsed > jump_end and wheel_contact)
def circular_procession(packet, drones, start_time) -> StepResult: """ Makes all cars drive in a slowly shrinking circle. https://gfycat.com/yearlygreathermitcrab """ radian_spacing = 2 * math.pi / len(drones) elapsed = packet.game_info.seconds_elapsed - start_time radius = 600 + elapsed * 25 for i, drone in enumerate(drones): progress = i * radian_spacing + elapsed * GROUND_PROCESSION_RATE target = [radius * math.sin(progress), radius * math.cos(progress), 0] slow_to_pos(drone, target) drone.ctrl.boost = False drone.ctrl.throttle = min(drone.ctrl.throttle, 0.3) return StepResult(finished=elapsed * GROUND_PROCESSION_RATE > 10 * math.pi)
def run_cnc(self, packet: GameTickPacket, drones: List[Drone], start_time) -> StepResult: game_time = packet.game_info.seconds_elapsed elapsed = game_time - start_time car_states = {} finished = True for i, extruder in enumerate(self.cnc_extruders): if i * 1 <= elapsed and not extruder.is_finished(): instruction_result = extruder.manipulate_drones(game_time) if instruction_result.car_states: car_states.update(instruction_result.car_states) finished = finished and instruction_result.finished if len(car_states): self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=finished)
def circular_procession(self, packet, drones, start_time) -> StepResult: """ Makes all cars drive in a slowly shrinking circle. https://gfycat.com/yearlygreathermitcrab """ radian_spacing = 2 * math.pi / len(drones) elapsed = packet.game_info.seconds_elapsed - start_time radius = 4000 - elapsed * 100 for i, drone in enumerate(drones): progress = i * radian_spacing + elapsed * .5 target = [ radius * math.sin(progress), radius * math.cos(progress), 0 ] slow_to_pos(drone, target) return StepResult(finished=radius < 10)
def delayed_start(self, packet, drones, start_time) -> StepResult: """ Spreads bots out by delaying the start of each row. """ elapsed = packet.game_info.seconds_elapsed - start_time for drone in drones: throttle_start = (drone.index % 32 // 8) * 0.85 drone.ctrl = SimpleControllerState() if throttle_start < elapsed: # Speed controller. vel = np.linalg.norm(drone.vel * np.array([1, 1, 0])) drone.ctrl.throttle = 0 if vel > 800 else 0.7 return StepResult(finished=elapsed > 4.5)
def circle_align(self, packet: GameTickPacket, drones, start_time) -> StepResult: self.ball.update(packet) self.game_interface.set_game_state( GameState(ball=BallState(physics=Physics( location=Vector3(drones[60].location.x, drones[60].location.y), velocity=Vector3(0, 0), angular_velocity=Vector3(*drones[60].raw_angular_velocity))))) for i, drone in enumerate(drones): self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed) if i == 60: break return StepResult( finished=packet.game_info.seconds_elapsed - start_time > 14)
def scatter(self, packet, drones, start_time) -> StepResult: """ Scatters the bots around the field randomly. """ car_states = {} for drone in drones: x = np.random.uniform(-4000, 4000) y = np.random.uniform(-5000, 5000) rot = np.random.uniform(-np.pi, np.pi) car_states[drone.index] = CarState( Physics(location=Vector3(x, y, 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, rot, 0))) self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=True)
def setup_circle_align(self, packet: GameTickPacket, drones, start_time) -> StepResult: self.ball.update(packet) self.game_interface.set_game_state( GameState(ball=BallState(physics=Physics( location=Vector3(drones[60].location.x, drones[60].location.y), velocity=Vector3(0, 0), angular_velocity=Vector3(*drones[60].raw_angular_velocity))))) radian_spacing = 2 * math.pi / 20 radian_spacing_v = 2 * math.pi / 10 for i, drone in enumerate(drones): if i == 60: self.drone_aerials[i].target = Vector(0, 0, 1000) else: # 0 & 1: center circle # 2, 3, 4, & 5: side circles group = i % 6 if group < 2: progress = (i // 6 * 2 + group) * radian_spacing self.drone_aerials[i].target = Vector( radius2 * math.sin(progress), radius2 * math.cos(progress), 1000) elif group < 4: progress = (i // 6 * 2 + (group - 2)) * radian_spacing Q = radius3 * math.sin(progress) adjusted_radius = radius2 + Q self.drone_aerials[i].target = Vector( adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), 1000 + Q) else: progress = (i // 6 * 2 + (group - 4)) * radian_spacing Q = radius3 * math.sin(progress) adjusted_radius = radius2 - Q self.drone_aerials[i].target = Vector( adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), 1000 - Q) self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed) if i == 60: break return StepResult(finished=True)
def line_up(self, packet, drones, start_time) -> StepResult: """ Puts all the cars in a tidy line, very close together. """ start_x = -2000 y_increment = 100 start_y = -len(drones) * y_increment / 2 start_z = 40 car_states = {} for drone in drones: car_states[drone.index] = CarState( Physics(location=Vector3(start_x, start_y + drone.index * y_increment, start_z), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0))) self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=True)
def place_near_ceiling(self, packet, drones, start_time) -> StepResult: """ Puts all the cars in a tidy line close to the ceiling. """ start_x = 2000 y_increment = 100 start_y = -len(drones) * y_increment / 2 start_z = 1900 car_states = {} for drone in drones: car_states[drone.index] = CarState( Physics(location=Vector3(start_x, start_y + drone.index * y_increment, start_z), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0), rotation=Rotator(math.pi * 1, 0, 0))) self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=True)
def make_square(self, packet, drones, start_time) -> StepResult: """ Gathers the bots in a 16 by 4 rectangle. """ x_spacing = 250 x_offset = 3 * x_spacing y_spacing = 140 y_offset = 3 * y_spacing / 2 car_states = {} for i, drone in enumerate(drones): car_states[drone.index] = CarState( Physics(location=Vector3(x_offset - x_spacing * (i % 16), y_offset - y_spacing * (i // 16), 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0))) self.game_interface.set_game_state(GameState(cars=car_states)) return StepResult(finished=True)
def setup(self, packet, drones, start_time) -> StepResult: self.game_interface.set_game_state( GameState(game_info=GameInfoState(game_speed=0.25))) car_states = {} radian_spacing = 2 * math.pi / 60 for index, drone in enumerate(drones): if 61 <= index <= 64: car_states[drone.index] = CarState( Physics(location=Vector3(3520, 5100, 0), velocity=Vector3(0, 0, 0))) continue if index == 60: car_states[drone.index] = CarState( Physics(location=Vector3(0, 0, 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0))) continue progress = index * radian_spacing target = Vec3(radius * math.sin(progress), radius * math.cos(progress), 0) car_states[drone.index] = CarState( Physics(location=Vector3(target.x, target.y, 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, -progress, 0))) self.game_interface.set_game_state( GameState(cars=car_states, ball=BallState( physics=Physics(location=Vector3(0, 0, 155), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0))))) return StepResult(finished=True)
def act_2(self, packet: GameTickPacket, drones, start_time) -> StepResult: self.ball.update(packet) if self.odd_tick % 2 == 0: self.game_interface.set_game_state( GameState(ball=BallState( physics=Physics(location=Vector3(drones[60].location.x, drones[60].location.y), velocity=Vector3(0, 0), angular_velocity=Vector3( *drones[60].raw_angular_velocity))))) radian_spacing = 2 * math.pi / 20 elapsed = packet.game_info.seconds_elapsed - start_time hover_height = 1022 - max(0, (elapsed - 60) * 100) # elapsed @ 16 seconds (1:06): foreshadow attack # elapsed @ 31 seconds (1:21): start attack # elapsed @ 60 seconds (1:50): attack center air dribbler then stop for i, drone in enumerate(drones): if i < 60: if drone.demolished: continue elif i not in self.alive_drones: self.alive_drones.append(i) # 0 & 1: center circle # 2, 3, 4, & 5: side circles group = i % 6 if group < 2: progress = (i // 6 * 2 + group) * radian_spacing + elapsed * .3 self.drone_aerials[i].target = Vector( radius2 * math.sin(progress), radius2 * math.cos(progress), hover_height) elif group < 4: progress = (i // 6 * 2 + (group - 2)) * radian_spacing + elapsed * .3 Q = radius3 * math.sin(progress) adjusted_radius = radius2 + Q self.drone_aerials[i].target = Vector( adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), hover_height + Q) else: progress = (i // 6 * 2 + (group - 4)) * radian_spacing + elapsed * .3 Q = radius3 * math.sin(progress) adjusted_radius = radius2 - Q self.drone_aerials[i].target = Vector( adjusted_radius * math.sin(progress), adjusted_radius * math.cos(progress), hover_height - Q) self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed) if i == 60: break if elapsed >= 31: if elapsed - self.last_demo_time >= demo_cooldown: car_states = {} for i in (61, 62): # (61, 62, 63) target = drones[self.get_random_demo_target( )] if elapsed < 60 else drones[60] car_states[i] = CarState( physics=Physics(location=Vector3( target.location.x - 100, target.location.y, target.location.z), velocity=Vector3(2300, 0, 0), rotation=Vector3(0, 0, 0))) if elapsed >= 60: self.attacked_center = True self.game_interface.set_game_state(GameState(cars=car_states)) self.last_demo_time = elapsed return StepResult(finished=elapsed > 63)
def act_2_end(self, packet: GameTickPacket, drones, start_time) -> StepResult: return StepResult( finished=packet.game_info.seconds_elapsed - start_time > 10)
def end_choreo(self, packet, drones, start_time) -> StepResult: self.game_interface.set_game_state( GameState(ball=BallState(Physics(location=Vector3(0, 5300, 400))))) return StepResult(finished=True)
def spin_around_rising_ball(self, packet, drones, start_time) -> StepResult: return StepResult(finished=True)
def drones_are_boids(self, packet, drones, start_time) -> StepResult: """ Controls the drones to act like boids. """ # Parameters: PERCEPTION_DIS = 800 ALIGNMENT_MUL = 100 COHESION_MUL = 150 SEPARATION_MUL = 200 AVOID_WALL_MUL = 500 for drone in drones: # Resetting drone controller. drone.ctrl = SimpleControllerState() # Creating "forces" alignment_vec = np.zeros(3) cohesion_vec = np.zeros(3) separation_vec = np.zeros(3) avoid_walls_vec = np.zeros(3) others = 0 # The amount of drones in perception dist. for other in drones: # Skip if the other is also the drone. if other is drone: continue other_to_drone = drone.pos - other.pos distance = np.linalg.norm(other_to_drone) # Skip if other is too far. if distance > PERCEPTION_DIS: continue # Increment others. others += 1 # Alignment alignment_vec += other.vel # Cohesion cohesion_vec += other.pos # Separation separation_vec += other_to_drone / distance**2 # Avoid Walls. if drone.pos[0] < -2800: avoid_walls_vec += np.array([1, 0, 0]) elif drone.pos[0] > 2800: avoid_walls_vec += np.array([-1, 0, 0]) if drone.pos[1] < -3800: avoid_walls_vec += np.array([0, 1, 0]) elif drone.pos[1] > 3800: avoid_walls_vec += np.array([0, -1, 0]) # Averaging out cohesion_vec # and making it relative to drone. if others > 0: cohesion_vec / others cohesion_vec -= drone.pos # Create seek target. target = np.zeros(3) target += ALIGNMENT_MUL * normalize(alignment_vec) target += COHESION_MUL * normalize(cohesion_vec) target += SEPARATION_MUL * normalize(separation_vec) target += AVOID_WALL_MUL * normalize(avoid_walls_vec) target += drone.pos # Follow target. seek_pos(drone, target, max_speed=1000) # Never finishes. return StepResult(finished=False)
def arrange_in_ground_circle(self, packet, drones, start_time) -> StepResult: elapsed = packet.game_info.seconds_elapsed - start_time arrange_in_ground_circle(drones, self.game_interface, 3000, elapsed * GROUND_PROCESSION_RATE) return StepResult(finished=True)