class Paul(BaseAgent): def initialize_agent(self): #self.gui = GUI() #Paul has a nice GUI that allows for drawing paths, creating and moving/editing events self.info = GameInfo(self.index, self.team) team = 0 if self.team == 1: team = -1 else: team = 1 self.action_state = '' self.frames = 0 self.yeet_start = time.time() self.yeet_kick_off = KickoffAgent('eat ass', self.info.team, self.info.index) self.last_frame = False self.flip_idx = 0 self.lock = threading.Lock() self.fps = 60 self.jump_frames = 0 self.kick = True self.car_locations = [ Queue(maxsize=4), Queue(maxsize=4), Queue(maxsize=4), Queue(maxsize=4), Queue(maxsize=4), Queue(maxsize=4) ] #self.orange_kickoff_hierarchy = [[2048, -2560, 0], [-2048, -2560, 0], [256, -3840, 0], [-256, -3840, 0]] def get_output(self, packet): self.info.read_packet(packet) game = self.convert_packet_to_v3( packet ) #Paul is a V3 Bot, a rework of preprocessing would be needed to re-optimize it self.frames = self.frames + 1 self.renderer.begin_rendering() self.renderer.draw_string_2d(50, 50, 5, 5, str(time.time() - self.yeet_start), self.renderer.red()) self.renderer.end_rendering() self.fps = self.frames / (time.time() - self.yeet_start) output = Bot.Process(self, game, packet, self.info, self.lock) controls = self.convert_output_to_v4(output) if (packet.game_info.is_kickoff_pause): controls = self.yeet_kick_off.get_output( packet, self.frames / (time.time() - self.yeet_start)) self.last_frame = True return controls else: self.kick = True self.yeet_kick_off = KickoffAgent('eat ass', self.info.team, self.info.index) return controls def is_hot_reload_enabled(self): return False
class Agent(BaseAgent): def __init__(self, name, team, index): self.info = GameInfo(index, team) self.controls = SimpleControllerState() self.action = None self.counter = 0 def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) if self.action == None or self.action.finished or self.counter == 400: target_pos = vec3( random.uniform(-3000, 3000), random.uniform(-2000, 2000), 25 ) target_speed = random.uniform(500, 2000) self.action = Drive(self.info.my_car, target_pos, target_speed) self.counter = 0 r = 200 self.renderer.begin_rendering() purple = self.renderer.create_color(255, 230, 30, 230) self.renderer.draw_line_3d(self.action.target_pos - r * vec3(1, 0, 0), self.action.target_pos + r * vec3(1, 0, 0), purple) self.renderer.draw_line_3d(self.action.target_pos - r * vec3(0, 1, 0), self.action.target_pos + r * vec3(0, 1, 0), purple) self.renderer.draw_line_3d(self.action.target_pos - r * vec3(0, 0, 1), self.action.target_pos + r * vec3(0, 0, 1), purple) self.renderer.end_rendering() if controller.L1: self.controls = controller.get_output() else: self.counter += 1 if (self.counter % 10) == 0: print(f"current speed: {norm(self.info.my_car.vel):4.4f}, \ desired speed: {self.action.target_speed:4.4f}") self.action.step(0.01666) self.controls = self.action.controls return self.controls
class ATBA(BaseAgent): def initialize_agent(self): self.info = GameInfo(self.index, self.team) def get_output(self, packet: GameTickPacket) -> SimpleControllerState: return SimpleControllerState() def atba_fast(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) return self.drive_controls(self.info.ball.pos, target_speed=Speed.fast) def atba_normal(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) return self.drive_controls(self.info.ball.pos, target_speed=Speed.normal) def atba_slow(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) return self.drive_controls(self.info.ball.pos, target_speed=Speed.slow) def atba_wait(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) return self.drive_controls(self.info.ball.pos, target_speed=Speed.stop) def drive_controls(self, target, target_speed): self.action = self.action = Drive(self.info.my_car, target_pos = target, target_speed=target_speed) self.action.step(1/60) return self.action.controls
class KickoffAgent(): def __init__(self, name, team, index): #This runs once before the bot starts up self.controller_state = SimpleControllerState() self.info = GameInfo(index, team) self.state = 'init' self.team = team def get_output(self, packet: GameTickPacket, fps) -> SimpleControllerState: self.info.read_packet(packet) if (self.state == 'init'): self.hit = Kickoff(info=self.info, fps=fps) self.state = 'run' #creating a basis for the field return self.hit.execute(self.info, fps).to_simple_controller_state()
class Snek(BaseAgent): def __init__(self, name, team, index): super().__init__(name, team, index) self.info = GameInfo(index, team) self.last_turn = 0 self.controls = SimpleControllerState() self.controls.throttle = 1 self.controls.boost = 1 def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) halfpi = math.pi / 2 car = self.info.my_car ball = self.info.ball delta_local = dot(ball.pos - car.pos, car.theta) ang = math.atan2(delta_local[1], delta_local[0]) car_state = CarState(boost_amount=100) if ang > math.pi / 2 and self.last_turn + TURN_COOLDOWN < time.time(): self.last_turn = time.time() m = axis_rotation(vec3(0, 0, halfpi)) nvel = dot(m, car.vel) nyaw = packet.game_cars[self.index].physics.rotation.yaw + halfpi car_state.physics = Physics(velocity=Vector3( nvel[0], nvel[1], nvel[2]), rotation=Rotator(pitch=0, roll=0, yaw=nyaw)) if -ang > math.pi / 2 and self.last_turn + TURN_COOLDOWN < time.time(): self.last_turn = time.time() m = axis_rotation(vec3(0, 0, -halfpi)) nvel = dot(m, car.vel) nyaw = packet.game_cars[self.index].physics.rotation.yaw - halfpi car_state.physics = Physics(velocity=Vector3( nvel[0], nvel[1], nvel[2]), rotation=Rotator(pitch=0, roll=0, yaw=nyaw)) game_state = GameState(cars={self.index: car_state}) self.set_game_state(game_state) return self.controls
class recover(): def __init__(self, master=None, agent=None, car=None, target=None, speed=None): self.name = 'RECOVER' self.master = master self.agent = agent self.car = car self.target = target self.speed = speed self.controls = SimpleControllerState() self.expired = False self.Ginfo = GameInfo(agent.index, agent.team) def update(self, master=None, agent=None, car=None, target=None, speed=None): self.master = master self.agent = agent self.car = car self.target = target self.speed = speed self.Ginfo = GameInfo(agent.index, agent.team) def available(self): return not self.car.has_wheel_contact def step(self, tick): self.Ginfo.read_packet(self.agent.packet) action = AerialTurn(self.Ginfo.my_car) action.step(tick) action.controls.throttle = 1 self.expired = action.finished self.expired = self.car.has_wheel_contact return action.controls
class BaseTestAgent(BaseAgent): def __init__(self, name, team, index): super(BaseTestAgent, self).__init__(name, team, index) self.action = self.create_action() self.info = GameInfo(index, team) def get_output(self, game_tick_packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(game_tick_packet) self.test_process(game_tick_packet) return self.action.get_output(self.info) def create_action(self) -> BaseAction: raise NotImplementedError def test_process(self, game_tick_packet: GameTickPacket): raise NotImplementedError def initialize_agent(self): raise NotImplementedError
class TorusChoreography(Choreography): def __init__(self, game_interface: GameInterface): super().__init__() self.game_interface = game_interface self.game_info = GameInfo(0, 0) self.renderer = self.game_interface.renderer self.drones_per_ring = 8 def pre_step(self, packet: GameTickPacket, drones: List[Drone]): self.game_info.read_packet(packet) @staticmethod def get_num_bots(): return 48 def generate_sequence(self, drones): self.sequence.clear() if len(drones) == 0: return pause_time = 0.2 self.sequence.append(HideBall()) self.sequence.append(LetAllCarsSpawn(self.get_num_bots())) self.sequence.append( BlindBehaviorStep(SimpleControllerState(), pause_time)) num_rings = len(drones) // self.drones_per_ring torus_period = 2 * math.pi / TORUS_RATE self.sequence.append( SubGroupOrchestrator(group_list=[ TorusSubChoreography( self.game_interface, self.game_info, -i * torus_period / num_rings, drones[i * self.drones_per_ring:(i + 1) * self.drones_per_ring], 0) for i in range(0, num_rings) ]))
class AerialStep(Step): """ This uses the Aerial controller provided by RLUtilities. Thanks chip! It will take care of jumping off the ground and flying toward the target. This will only work properly if you call tick repeatedly on the same instance. """ def __init__(self, target: Vec3, arrival_time: float, index: int): self.index = index self.aerial: Aerial = None self.game_info: GameInfo = None self.target = target self.arrival_time = arrival_time def tick(self, packet: GameTickPacket) -> StepResult: if self.game_info is None: self.game_info = GameInfo(self.index, packet.game_cars[self.index].team) self.game_info.read_packet(packet) if self.aerial is None: self.aerial = Aerial( self.game_info.my_car, vec3(self.target.x, self.target.y, self.target.z), self.arrival_time) self.aerial.step(SECONDS_PER_TICK) controls = SimpleControllerState() controls.boost = self.aerial.controls.boost controls.pitch = self.aerial.controls.pitch controls.yaw = self.aerial.controls.yaw controls.roll = self.aerial.controls.roll controls.jump = self.aerial.controls.jump return StepResult(controls, packet.game_info.seconds_elapsed > self.arrival_time)
class Agent(BaseAgent): def __init__(self, name, team, index): self.index = index self.info = GameInfo(index, team) self.controls = SimpleControllerState() self.skip = False self.timer = 0.0 self.action = None self.car_predictions = [] self.ball_predictions = [] self.csign = 1; self.bsign = 1; def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) self.controls = SimpleControllerState() if self.timer == 0.0: self.csign = random.choice([-1, 1]) # this just initializes the car and ball # to different starting points each time c_position = Vector3(random.uniform(-1000, 1000), random.uniform(-4500, -4000), 25) car_state = CarState(physics=Physics( location=c_position, velocity=Vector3(0, 1000, 0), rotation=Rotator(0, 1.5 * self.csign, 0), angular_velocity=Vector3(0, 0, 0) )) self.bsign = random.choice([-1, 1]) b_position = Vector3(random.uniform(-3500, -3000) * self.bsign, random.uniform(-1500, 1500), random.uniform( 150, 500)) b_velocity = Vector3(random.uniform( 1000, 1500) * self.bsign, random.uniform(- 500, 500), random.uniform( 1000, 1500)) ball_state = BallState(physics=Physics( location=b_position, velocity=b_velocity, rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0) )) self.set_game_state(GameState( ball=ball_state, cars={self.index: car_state}) ) self.increment_timer = True if self.timer < 0.3: self.controls.throttle = 1 * self.csign else: if self.action == None: # set empty values for target and t_arrival initially self.action = Aerial(self.info.my_car, vec3(0,0,0), 0) # predict where the ball will be prediction = Ball(self.info.ball) self.ball_predictions = [vec3(prediction.pos)] for i in range(150): prediction.step(0.016666) prediction.step(0.016666) self.ball_predictions.append(vec3(prediction.pos)) # if the ball is in the air if prediction.pos[2] > 100: self.action.target = prediction.pos self.action.t_arrival = prediction.t # check if we can reach it by an aerial if self.action.is_viable(): break nsteps = 30 delta_t = self.action.t_arrival - self.info.my_car.time prediction = Car(self.info.my_car) self.car_predictions = [vec3(prediction.pos)] for i in range(nsteps): prediction.step(Input(), delta_t / nsteps) self.car_predictions.append(vec3(prediction.pos)) r = 200 self.renderer.begin_rendering() purple = self.renderer.create_color(255, 230, 30, 230) white = self.renderer.create_color(255, 230, 230, 230) x = vec3(r,0,0) y = vec3(0,r,0) z = vec3(0,0,r) target = self.action.target future = self.action.target - self.action.A self.renderer.draw_polyline_3d(self.ball_predictions, purple) self.renderer.draw_line_3d(target - x, target + x, purple) self.renderer.draw_line_3d(target - y, target + y, purple) self.renderer.draw_line_3d(target - z, target + z, purple) self.renderer.draw_polyline_3d(self.car_predictions, white) self.renderer.draw_line_3d(future - x, future + x, white) self.renderer.draw_line_3d(future - y, future + y, white) self.renderer.draw_line_3d(future - z, future + z, white) self.renderer.end_rendering() self.action.step(1.0 / 60.0) self.controls = self.action.controls if self.action.finished or self.timer > 10.0: self.timer = 0.0 self.action = None self.increment_timer = False self.predictions = [] if self.increment_timer: self.timer += 1.0 / 60.0 self.info.my_car.last_input.roll = self.controls.roll self.info.my_car.last_input.pitch = self.controls.pitch self.info.my_car.last_input.yaw = self.controls.yaw self.info.my_car.last_input.boost = self.controls.boost return self.controls
class BallPredictor: def __init__(self, index, team): self.index = index self.mass_car = 2.4 self.mass_ball = 4.5 self.car = CarModel(index) self.info = GameInfo(index, team) def update(packet): self.info.read_packet(packet) self.car.update(packet) def get_path( time, dt ): path = [] t, path1, path2=self.will_hit( ball, self.car, time ) newvel = self.predict_ball(ball, self.car) ball = Ball( self.info.ball ) swapped = False for i in range(int(time/dt)): ball.step(dt) path.append(vec3(ball.pos)) if i > t and not swapped: ball.vel = vec3(newvel[0].item(), newvel[1].item(), newvel[2].item()) swapped = True return path def get_step( self, p1, p2 ): #Really bad Approximation distance = self.distance( p1, p2 ) slopes = (p2 - p1)/distance return slopes def get_impact_point( self, loc ): step = self.get_step( self.car_pos, loc ) current = self.car_pos while self.point_in_car( current ): current = current + step return current def point_in_car( self, point ): point = point - self.car_pos point = self.rotate_axis(point, -self.car_rot[0], 0) point = self.rotate_axis(point, -self.car_rot[1], 1) point = self.rotate_axis(point, -self.car_rot[2], 2) between = [] for i in range(3): between.append( -self.car_dims[i].item()/2 < point[i].item() and point[i].item() < self.car_dims[i].item()/2 ) return between[0] and between[1] and between[2] def rotate_axis( self, x, rotation, axis ): x = x.unsqueeze(0) if axis == 0: r_x = rotation R_x = np.array([[1, 0, 0], [0, r_x.cos(), -1*r_x.sin()], [0, r_x.sin(), r_x.cos()]]) x = np.dot( x, R_x ) if axis == 1: r_y = rotation R_y = np.array([[r_y.cos(), 0, r_y.sin()], [0, 1, 0], [-1*r_y.sin(), 0, r_y.cos()]]) x = np.dot(x, R_y) if axis == 2: r_z = rotation R_z = np.array([[r_z.cos(), -1*r_z.sin(), 0], [r_z.sin(), r_z.cos(), 0], [0, 0, 1]]) x = np.dot(x, R_z) return x[0] def distance( self, p1, p2 ): return np.sum( (p1 - p2)**2 )**0.5 def predict_ball(self, ball_info, player_info): ball_pos, ball_vel, ball_avel = self.parse_ball_info( ball_info ) self.car_pos, self.car_vel, self.car_rot, self.car_avel = player_info.pos, player_info.vel, player_info.rot, player_info.avel impact_pos = self.get_impact_point( ball_pos ) impact_step_dir = self.get_step( impact_pos, ball_pos ) # This will not be accurate at all! magnitude = self.distance(self.car_vel * self.mass_car, ball_vel * self.mass_ball) J = impact_step_dir * magnitude # This will be more accurate J_final = J #+ self.impulse_correction return ball_vel + J_final/self.mass_ball def parse_ball_info(self, ball): ball_pos = np.array([ball.pos[0], ball.pos[1], ball.pos[2]]) ball_vel = np.array([ball.vel[0], ball.vel[1], ball.vel[2]]) ball_avel = np.array([ball.omega[0], ball.omega[1], ball.omega[2]]) return ball_pos, ball_vel, ball_avel
class Agent(BaseAgent): def __init__(self, name, team, index): self.index = index self.info = GameInfo(index, team) self.controls = SimpleControllerState() self.timer = 0.0 self.timeout = 3.0 self.action = None self.state = State.RESET def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) self.controls = SimpleControllerState() next_state = self.state if self.state == State.RESET: self.timer = 0.0 # put the car in the middle of the field car_state = CarState( physics=Physics(location=Vector3(0, 0, 20), velocity=Vector3(1000, 0, 0), rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) # put the ball somewhere out of the way ball_state = BallState( physics=Physics(location=Vector3(0, -3000, 100), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) self.set_game_state( GameState(ball=ball_state, cars={self.index: car_state})) next_state = State.WAIT if self.state == State.WAIT: if self.timer > 0.2: next_state = State.INITIALIZE if self.state == State.INITIALIZE: self.action = HalfFlip(self.info.my_car) next_state = State.RUNNING if self.state == State.RUNNING: self.action.step(0.01666) self.controls = self.action.controls if self.timer > self.timeout: next_state = State.RESET self.timer += 0.01666 self.state = next_state return self.controls
class AgentModule: def __init__( self, agent, bot_container, model1_path=None, model2_path=None, save_path=None, mode=0, render=False, ): """ AgentModule. agent: The agent that this is running on model1_path: Path to load model to be trained from. Defaults to making a new one. model2_path: Path to load model to be learned from (Used for transfer learning only). save_path: Path to save the model being trained (Used only when mode is not 0). Defaults to not saving. mode: 0 - Just playing the game. 1 - Real time learning from human teacher (Rendering should be enabled). 2 - Transfer learning from model specified in model2. render: Boolean, forced rendering when mode = 1 """ self.training_history = [[], []] self.count = 1 self.ticks_per_update = 60 * 60 #~60 seconds self.save_path = save_path model2_bot_num = 0 self.flags = { "render": render or mode == 1, "train": mode == 1, "transfer": mode == 2 } if self.flags["train"] and self.flags["transfer"]: raise Exception("Both train and transfer flags cannot be true.") self.info = GameInfo(agent.index, agent.team) self.bots = bot_container(agent) self.ui = TrainingUI(self.bots) self.model = ModelBox(self.bots.num_bots(), agent.index, agent.team) self.controls = SimpleControllerState() self.reader = None if self.flags["train"] or self.flags["transfer"]: from keyboard_interface import reader self.reader = reader self.reader.set_bot_num(self.bots.num_bots()) if model1_path != None: self.model.load(model1_path) if self.flags["transfer"]: self.model2 = ModelBox(model2_bot_num, agent.index, agent.team) if model2_path != None: self.model2.load(model2_path) self.paused = True def get_output(self, packet: GameTickPacket, renderer=None) -> SimpleControllerState: self.info.read_packet(packet) bot_index = self.model.predict(packet=packet) if self.flags["train"] and not self.reader.training_paused: self.training_history[0].append(self.reader.intended_index) self.training_history[1].append(packet) if self.count % self.ticks_per_update == 0: self.model.fit(self.training_history[0], packets=self.training_history[1]) if not self.paused and self.reader.training_paused and self.save_path != None: self.model.save(self.save_path) if self.flags["transfer"]: self.training_history[0].append(self.reader.intended_index) self.training_history[1].append(packet) if self.count % self.ticks_per_update == 0: self.model2.fit(self.training_history[0], packets=self.training_history[1]) bot_index = self.model2.predict(packet=packet) self.count += 1 if self.flags["render"]: if renderer == None: raise ValueError( "Must specify renderer when rendering is used (mode is 1 or render is true)" ) renderer.begin_rendering() if self.reader != None: self.ui.update_tick(bot_index, self.reader.intended_index) renderer.draw_string_2d( 220, 0, 2, 2, "Paused: " + str(self.reader.training_paused), renderer.white()) else: self.ui.update_tick(bot_index, -1) self.ui.render(renderer) renderer.end_rendering() self.paused = self.reader.training_paused if self.paused: return self.bots.get_bot(index=self.reader.intended_index)(packet) return self.bots.get_bot(index=bot_index)(packet)
class Agent(BaseAgent): def __init__(self, name, team, index): self.index = index self.info = GameInfo(index, team) self.controls = SimpleControllerState() self.timer = 0.0 self.timeout = 2.0 self.action = None self.state = State.RESET def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) self.controls = SimpleControllerState() next_state = self.state if self.state == State.RESET: self.timer = 0.0 # put the car in the middle of the field car_state = CarState( physics=Physics(location=Vector3(0, 0, 20), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) theta = random.uniform(0, 6.28) pos = Vector3(sin(theta) * 1000.0, cos(theta) * 1000.0, 100.0) # put the ball somewhere out of the way ball_state = BallState( physics=Physics(location=pos, velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) self.set_game_state( GameState(ball=ball_state, cars={self.index: car_state})) next_state = State.WAIT if self.state == State.WAIT: if self.timer > 0.2: next_state = State.INITIALIZE if self.state == State.INITIALIZE: # in this demonstration, we choose to dodge toward the ball c = self.info.my_car target = self.info.ball.pos self.action = AirDodge(c, 0.1, target) next_state = State.RUNNING if self.state == State.RUNNING: self.action.step(0.01666) self.controls = self.action.controls if self.timer > self.timeout: next_state = State.RESET self.timer += 0.01666 self.state = next_state return self.controls
class LeviAgent(BaseAgent): def __init__(self, name, team, index): super().__init__(name, team, index) sys.path.insert(0, path) # this is for separate process imports import torch self.torch = torch self.empty_controller = SimpleControllerState() self.model_path = None self.model = None self.input_formatter = None self.output_formatter = None self.expected_time = None self.mood = 0.0 # initialize kickoff self.info = None self.drive = None self.dodge = None self.controls = SimpleControllerState() self.kickoff = False self.kickoffStart = None self.time = 0 self.FPS = 1 / 120 self.kickoffTime = 0 def load_config(self, config_object_header: ConfigHeader): self.model_path = config_object_header.get('model_path') def initialize_agent(self): self.model = self.get_model() self.input_formatter = self.create_input_formatter() self.output_formatter = self.create_output_formatter() self.model.load_state_dict(self.torch.load(self.get_file_path())) # initialize kickoff self.info = GameInfo(self.index, self.team, self.get_field_info()) def get_file_path(self): return os.path.join(path, self.model_path) def get_output(self, packet): """ Predicts an output given the input :param packet: The game_tick_packet :return: """ if not packet.game_info.is_round_active: # self.time = None return self.empty_controller if packet.game_cars[self.index].is_demolished: return self.empty_controller if self.time >= packet.game_info.seconds_elapsed: return self.empty_controller # kickoffs self.FPS = packet.game_info.seconds_elapsed - self.time self.time = packet.game_info.seconds_elapsed self.info.read_packet(packet) self.set_mechanics() prev_kickoff = self.kickoff self.kickoff = packet.game_info.is_kickoff_pause if self.kickoff and not prev_kickoff: init_kick_off(self) if self.kickoff: kick_off(self) return self.controls # ML control arr = self.input_formatter.create_input_array([packet], batch_size=1) assert (arr[0].shape == (1, 3, 9)) assert (arr[1].shape == (1, 5)) output = self.advanced_step(arr) return self.output_formatter.format_model_output(output, [packet], batch_size=1)[0] def set_mechanics(self): if self.drive is None: self.drive = Drive(self.info.my_car, self.info.ball.pos, 1399) if self.dodge is None: self.dodge = AirDodge(self.info.my_car, 0.25, self.info.ball.pos) def create_input_formatter(self): return LeviInputFormatter(self.team, self.index) def create_output_formatter(self): return LeviOutputFormatter(self.index) def get_model(self): from torch_model import SymmetricModel return SymmetricModel() def advanced_step(self, arr): arr = [self.torch.from_numpy(x).float() for x in arr] with self.torch.no_grad(): output, t = self.model.forward(*arr) self.quick_chat(t) return output @staticmethod def create_agent_configurations(config: ConfigObject): super(LeviAgent, LeviAgent).create_agent_configurations(config) params = config.get_header(BOT_CONFIG_AGENT_HEADER) params.add_value('model_path', str, default=os.path.join('models', 'cool_atba.mdl'), description='Path to the model file') def quick_chat(self, t): new_time = t.mean.item() if self.expected_time is None: self.expected_time = new_time return self.mood *= 0.995 self.mood += (self.expected_time - new_time) * 0.005 if self.mood > 0.075: self.send_quick_chat(False, random.choice(positive)) self.mood = 0 if self.mood < -0.075: self.send_quick_chat(False, random.choice(negative)) self.mood = 0 self.expected_time = new_time
class Agent(BaseAgent): def __init__(self, name, team, index): self.info = GameInfo(index, team) self.controls = SimpleControllerState() def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) ball = self.info.ball car = self.info.my_car # the vector from the car to the ball in local coordinates: # delta_local[0]: how far in front of my car # delta_local[1]: how far to the left of my car # delta_local[2]: how far above my car delta_local = dot(ball.pos - car.pos, car.theta) # the angle between the direction the car is facing # and the in-plane local position of the ball phi = math.atan2(delta_local[1], delta_local[0]) # a simple steering controller that is proportional to phi self.controls.steer = clip(2.5 * phi, -1.0, 1.0) # just set the throttle to 1 so the car is always moving forward self.controls.throttle = 1.0 # draw some of the lines showing the angle phi (purple) # and the local coordinates: # delta_local[0]: red # delta_local[1]: green # delta_local[2]: blue self.renderer.begin_rendering() red = self.renderer.create_color(255, 255, 30, 30) green = self.renderer.create_color(255, 30, 255, 30) blue = self.renderer.create_color(255, 30, 30, 255) white = self.renderer.create_color(255, 230, 230, 230) gray = self.renderer.create_color(255, 130, 130, 130) purple = self.renderer.create_color(255, 230, 30, 230) f = car.forward() l = car.left() u = car.up() self.renderer.draw_line_3d(car.pos, car.pos + delta_local[0] * f, red) self.renderer.draw_line_3d(car.pos, car.pos + delta_local[1] * l, green) self.renderer.draw_line_3d(car.pos, car.pos + delta_local[2] * u, blue) self.renderer.draw_line_3d(car.pos, ball.pos, white) self.renderer.draw_line_3d(ball.pos, ball.pos - delta_local[2] * u, gray) self.renderer.draw_line_3d(car.pos, ball.pos - delta_local[2] * u, gray) radius = 200 num_segments = 30 angle = [] for i in range(num_segments): c = math.cos(phi * float(i) / (num_segments - 1)) s = math.sin(phi * float(i) / (num_segments - 1)) angle.append(car.pos + radius * (c * f + s * l)) self.renderer.draw_polyline_3d(angle, purple) self.renderer.end_rendering() if controller.L1: self.controls = controller.get_output() return self.controls
class SniperBot(BaseAgent): AIMING = 0 FLYING = 1 KICKOFF = 2 def __init__(self, name, team, index): super().__init__(name, team, index) self.controls = SimpleControllerState() self.info = GameInfo(self.index, self.team) self.t_index = 0 self.standby_position = vec3(0, 0, 300) self.direction = vec3(0, 0, 1) self.state = self.KICKOFF self.shoot_time = 0 self.last_pos = self.standby_position self.last_elapsed_seconds = 0 self.kickoff_timer_edge = False self.ball_moved = False self.next_is_super = False self.doing_super = False self.hit_pos = vec3(0, 0, 0) self.standby_initiated = False def get_output(self, packet: GameTickPacket) -> SimpleControllerState: dt = packet.game_info.seconds_elapsed - self.last_elapsed_seconds self.last_elapsed_seconds = packet.game_info.seconds_elapsed self.info.read_packet(packet) ball_pos = self.info.ball.pos if not self.standby_initiated: self.initiate_standby(packet) if ball_pos[0] != 0 or ball_pos[1] != 0: self.ball_moved = True if ball_pos[0] == 0 and ball_pos[ 1] == 0 and self.info.my_car.boost == 34 and not self.state == self.KICKOFF and self.ball_moved: # Ball is placed at the center - assume kickoff self.state = self.KICKOFF self.ball_moved = False if self.state == self.KICKOFF: if packet.game_info.is_kickoff_pause: self.kickoff_timer_edge = True if ball_pos[0] != 0 or ball_pos[1] != 0 or ( self.kickoff_timer_edge and not packet.game_info.is_kickoff_pause): self.shoot_time = self.info.time + AIM_DURATION_AFTER_KICKOFF + self.t_index self.controls.boost = False self.controls.roll = 0 self.kickoff_timer_edge = False self.state = self.AIMING self.last_pos = self.standby_position elif self.state == self.AIMING: self.controls.boost = False self.controls.roll = 0 self.hit_pos = self.predict_hit_pos() self.direction = d = normalize(self.hit_pos - self.standby_position) rotation = Rotator(math.asin(d[2]), math.atan2(d[1], d[0]), 0) car_state = CarState( Physics(location=to_fb(self.standby_position), velocity=Vector3(0, 0, 0), rotation=rotation, angular_velocity=Vector3(0, 0, 0))) game_state = GameState(cars={self.index: car_state}) self.set_game_state(game_state) self.render_aiming(self.hit_pos) if self.shoot_time < self.info.time: self.state = self.FLYING if self.next_is_super: self.doing_super = True self.next_is_super = False else: self.doing_super = False elif self.state == self.FLYING: speed = SUPER_SPEED if self.doing_super else NORMAL_SPEED vel = self.direction * speed n_pos = self.last_pos + vel * dt car_state = CarState( Physics(location=to_fb(n_pos), velocity=to_fb(vel))) game_state = GameState(cars={self.index: car_state}) self.set_game_state(game_state) self.last_pos = n_pos self.controls.boost = self.doing_super self.controls.roll = self.doing_super if abs(n_pos[0]) > 4080 or abs( n_pos[1]) > 5080 or n_pos[2] < 0 or n_pos[2] > 2020: # Crash self.state = self.AIMING self.shoot_time = self.info.time + AIM_DURATION self.last_pos = self.standby_position self.next_is_super = self.info.my_car.boost >= 99 self.render_aiming(self.hit_pos) return self.controls def predict_hit_pos(self): speed = SUPER_SPEED if self.next_is_super else NORMAL_SPEED ball_prediction = self.get_ball_prediction_struct() if ball_prediction is not None: TIME_PER_SLICES = 1 / 60.0 SLICES = 360 # Iterate to find the first location which can be hit for i in range(0, 360): time = i * TIME_PER_SLICES rlpos = ball_prediction.slices[i].physics.location pos = vec3(rlpos.x, rlpos.y, rlpos.z) dist = norm(self.standby_position - pos) travel_time = dist / speed if time + TIME_PER_SLICES > travel_time: # Add small bias for aiming tsign = -1 if self.team == 0 else 1 enemy_goal = vec3(0, tsign * -5030, 300) bias_direction = normalize(pos - enemy_goal) pos = pos + bias_direction * GOAL_AIM_BIAS_AMOUNT return pos # Use last rlpos = ball_prediction.slices[SLICES - 1].physics.location return vec3(rlpos.x, rlpos.y, rlpos.z) return vec3(0, 0, 0) def render_aiming(self, pos): if self.state == self.AIMING or self.state == self.FLYING: self.renderer.begin_rendering() t = max(0, self.shoot_time - self.info.time) r = 50 + 400 * t self.draw_circle(pos, self.direction, r, 20 + int(r / (math.tau * 5))) if self.state != self.FLYING: l = self.direction * (70 + t * 100) self.renderer.draw_line_3d(pos - l, pos + l, self.renderer.team_color()) else: s = 70 x = vec3(s, 0, 0) y = vec3(0, s, 0) z = vec3(0, 0, s) self.renderer.draw_line_3d(pos - x, pos + x, self.renderer.team_color()) self.renderer.draw_line_3d(pos - y, pos + y, self.renderer.team_color()) self.renderer.draw_line_3d(pos - z, pos + z, self.renderer.team_color()) self.renderer.end_rendering() def draw_circle(self, center: vec3, normal: vec3, radius: float, pieces: int): # Construct the arm that will be rotated arm = normalize(cross(normal, center)) * radius angle = 2 * math.pi / pieces rotation_mat = axis_rotation(angle * normalize(normal)) points = [center + arm] for i in range(pieces): arm = dot(rotation_mat, arm) points.append(center + arm) self.renderer.draw_polyline_3d(points, self.renderer.team_color()) def initiate_standby(self, packet): self.standby_initiated = True snipers_on_team = 0 for i in range(0, packet.num_cars): car = packet.game_cars[i] if car.team == self.team: if car.name == self.name: self.t_index = snipers_on_team if car.name[:6] == "Sniper": snipers_on_team += 1 tsign = -1 if self.team == 0 else 1 z = 300 y = 5030 spacing = 400 if snipers_on_team == 1: self.standby_position = vec3(0, tsign * y, z) elif snipers_on_team == 2: self.standby_position = vec3(-400 + self.t_index * 800, tsign * y, z) else: # There are an even number of snipers on the team is_top_row = (self.t_index < snipers_on_team / 2) offset = spacing * (snipers_on_team - 2) / 4 row_index = self.t_index if is_top_row else self.t_index - snipers_on_team / 2 x = -offset + row_index * spacing self.standby_position = vec3(x, tsign * y, z + 150 * is_top_row)
class Calculator(BaseAgent): def __init__(self, name, team, index): self.index = index self.info = GameInfo(index, team) self.team = team self.controls = SimpleControllerState() self.action = None self.last_time = 0.0 self.dt = 1.0 / 120.0 self.goals = 0 self.timer = 0.0 self.kickoff_pos = None self.state = None self.target = None self.target_speed = 1800 self.drift = False #bot parameters self.target_range = 200 self.low_boost = 25 self.max_ball_dist = 4000 self.def_extra_dist = 800 self.turn_c_quality = 20 self.min_target_s = 1000 self.dodge_dist = 400 self.RLwindow = [0]*4 def get_output(self, packet): self.info.read_packet(packet) #additional processing not done by RLU self.kickoff_pause = packet.game_info.is_kickoff_pause self.round_active = packet.game_info.is_round_active self.dt = self.info.time - self.last_time self.last_time = self.info.time self.last_touch = packet.game_ball.latest_touch.player_name #trashtalk if packet.game_cars[self.index].score_info.goals == self.goals + 1: self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Reactions_Calculated) self.goals = packet.game_cars[self.index].score_info.goals #resets controls each tick self.controls = SimpleControllerState() #choose state if not self.round_active: self.state = None elif not self.state == "kickoff": if self.kickoff_pause: self.kickoff_pos = None self.action = None self.timer = 0.0 self.state = "kickoff" elif not self.info.my_car.on_ground and not isinstance(self.action, AirDodge): self.state = "recovery" self.action = self.action = AerialTurn(self.info.my_car) elif norm(self.info.my_goal.center - self.info.my_car.pos) > norm(self.info.my_goal.center - self.info.ball.pos) + self.def_extra_dist: self.action = None self.target_speed = 2300 self.state = "defence" if self.team == 0: sign = -1 else: sign = 1 #temporary 2v2 for Cow if len(self.info.teammates) > 0: if self.info.ball.pos[1] > 0: self.target = vec3(3000,sign*4000,0) else: self.target = vec3(-3000,sign*4000,0) else: self.target = vec3(0,sign*4000,0) elif self.info.my_car.pos[1] > 5120 or self.info.my_car.pos[1] < -5120: self.target = vec3(0,5000,0) if self.info.my_car.pos[1] > 5120 else vec3(0,-5000,0) self.action = self.action = Drive(self.info.my_car,self.target,1000) self.state = "goal escape" elif self.state == None: self.action = None self.target = None self.target_speed = 2300 self.state = "offence" #kickoff state if self.state == "kickoff": Kickoff.kickoff(self) #exit kickoff state if self.timer >= 2.6 or self.last_touch != '': self.state = None self.action = None #recovery state elif self.state == "recovery": self.action.step(self.dt) self.controls = self.action.controls self.controls.throttle = 1.0 #exit recovery state if self.info.my_car.on_ground == True: self.state = None self.action = None #defence state and offence state elif self.state == "defence" or self.state == "offence": #select target if self.target == None: #large boost if self.info.my_car.boost <= self.low_boost and norm(self.info.my_car.pos - self.info.ball.pos) > self.max_ball_dist: active_pads = [] for pad in self.info.boost_pads: if pad.is_active: active_pads.append(pad) if len(active_pads) != 0: closest_pad = active_pads[0] for pad in active_pads: if norm(pad.pos - self.info.ball.pos) < norm(closest_pad.pos - self.info.ball.pos): closest_pad = pad self.target = closest_pad.pos else: self.target = self.info.ball.pos #ball else: self.target = self.info.ball.pos forward_target = dot(self.target - self.info.my_car.pos, self.info.my_car.theta)[0] right_target = dot(self.target - self.info.my_car.pos, self.info.my_car.theta)[1] angle_to_target = math.atan2(right_target, forward_target) forward_goal = dot(self.info.their_goal.center - self.info.my_car.pos, self.info.my_car.theta)[0] right_goal = dot(self.info.their_goal.center - self.info.my_car.pos, self.info.my_car.theta)[1] angle_to_goal = math.atan2(right_goal, forward_goal) #select maneuver if not isinstance(self.action, AirDodge): #shooting if norm(self.info.ball.pos - self.info.my_car.pos) < self.dodge_dist and (angle_to_target - (math.pi/10.0) <= angle_to_goal <= angle_to_target + (math.pi/10.0)): self.action = AirDodge(self.info.my_car,0.2,self.info.their_goal.center) self.timer = 0.0 #dodging elif (-math.pi/24.0) <= angle_to_target <= (math.pi/24.0) and norm(self.info.my_car.vel) > 700 and norm(self.info.ball.pos - self.info.my_car.pos) > 1000 and not self.state == "defence": self.action = AirDodge(self.info.my_car,0.2,self.target) self.timer = 0.0 #Drive else: self.action = Drive(self.info.my_car,self.target,self.target_speed) #exit AirDodge else: self.timer += self.dt if self.timer >= 0.5: self.action = None #Drive if isinstance(self.action, Drive): speed = norm(self.info.my_car.vel) r = -6.901E-11 * speed**4 + 2.1815E-07 * speed**3 - 5.4437E-06 * speed**2 + 0.12496671 * speed + 157 #handbrake self.drift = False if (math.pi/2.0) <= angle_to_target or angle_to_target <= (-math.pi/2.0): self.drift = True #target speed elif (norm(self.target - (self.info.my_car.pos + dot(self.info.my_car.theta,vec3(0,r,0)))) < r or norm(self.target - (self.info.my_car.pos + dot(self.info.my_car.theta,vec3(0,-r,0)))) < r) and not self.target_speed < self.min_target_s: self.target_speed += -50 self.action = Drive(self.info.my_car,self.target,self.target_speed) elif self.target_speed < 1800: self.target_speed += 50 self.action = Drive(self.info.my_car,self.target,self.target_speed) #maneuver tick if self.action != None: self.action.step(self.dt) self.controls = self.action.controls self.controls.handbrake = self.drift #exit either state if (self.state == "defence" and norm(self.info.my_goal.center - self.info.my_car.pos) < norm(self.info.my_goal.center - self.info.ball.pos)) or (norm(self.target - self.info.my_car.pos) < self.target_range): self.state = None #goal escape state if self.state == "goal escape": self.action.step(self.dt) self.controls = self.action.controls #exit goal escape state if not (self.info.my_car.pos[1] > 5120 or self.info.my_car.pos[1] < -5120): self.state = None self.action = None if 'win32gui' in sys.modules: #finding the size of the Rocket League window def callback(hwnd, win_rect): if "Rocket League" in win32gui.GetWindowText(hwnd): rect = win32gui.GetWindowRect(hwnd) win_rect[0] = rect[0] win_rect[1] = rect[1] win_rect[2] = rect[2] - rect[0] win_rect[3] = rect[3] - rect[1] self.RLwindow = [0] * 4 win32gui.EnumWindows(callback, self.RLwindow) #Rendering Render.debug(self) Render.turn_circles(self) if not self.target == None: Render.target(self) return self.controls
class Agent(BaseAgent): def __init__(self, name, team, index): self.index = index self.info = GameInfo(index, team) self.controls = SimpleControllerState() self.timer = 0.0 self.action = None def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) self.controls = SimpleControllerState() if self.timer < 0.05: position = Vector3(random.uniform(-4000, 4000), random.uniform(-3000, 3000), random.uniform(500, 2000)) velocity = Vector3(random.uniform(-1500, 1500), random.uniform(-1500, 1500), random.uniform(-1000, -500)) rotation = Rotator(random.uniform(-1.5, 1.5), random.uniform(-1.5, 1.5), random.uniform(-1.5, 1.5)) angular_velocity = Vector3(random.uniform(-3.0, 3.0), random.uniform(-3.0, 3.0), random.uniform(-3.0, 3.0)) car_state = CarState( physics=Physics(location=position, velocity=velocity, rotation=rotation, angular_velocity=angular_velocity)) self.set_game_state(GameState(cars={self.index: car_state})) if self.timer > 0.10: if self.action == None: self.action = AerialTurn(self.info.my_car) self.renderer.begin_rendering() red = self.renderer.create_color(255, 255, 30, 30) self.renderer.draw_polyline_3d(self.action.trajectory, red) self.renderer.end_rendering() self.action.step(1.0 / 60.0) self.controls = self.action.controls self.timer += 1.0 / 60.0 if self.action.finished or self.timer > 5.0: print("target:\n", self.action.target) print("theta:\n", self.action.car.theta) print() self.timer = 0.0 self.action = None self.timer += 1.0 / 60.0 return self.controls
class hypebot(BaseAgent): def __init__(self, name, team, index): super().__init__(name, team, index) self.name = name self.team = team self.index = index self.defending = False self.info = None self.bounces = [] self.drive = None self.catching = None self.dodge = None self.recovery = None self.dribble = None self.controls = SimpleControllerState() self.kickoff = False self.inFrontOfBall = False self.kickoffStart = None self.step = "Catching" self.time = 0 self.FPS = 1 / 120 self.p_s = 0. self.kickoffTime = 0 def initialize_agent(self): self.info = GameInfo(self.index, self.team, self.get_field_info()) def get_output(self, packet: GameTickPacket) -> SimpleControllerState: if packet.game_info.seconds_elapsed - self.time > 0: self.FPS = packet.game_info.seconds_elapsed - self.time self.time = packet.game_info.seconds_elapsed self.info.read_packet(packet) self.predict() self.set_mechanics() prev_kickoff = self.kickoff self.kickoff = packet.game_info.is_kickoff_pause self.defending = self.should_defending() if self.kickoff and not prev_kickoff: initKickOff(self) if self.kickoff or self.step == "Dodge2": kickOff(self) else: self.get_controls() self.render_string(str(self.step)) if not packet.game_info.is_round_active: self.controls.steer = 0 return self.controls def predict(self): self.bounces = [] ball_prediction = self.get_ball_prediction_struct() for i in range(ball_prediction.num_slices): location = vec3(ball_prediction.slices[i].physics.location.x, ball_prediction.slices[i].physics.location.y, ball_prediction.slices[i].physics.location.z) prev_ang_vel = ball_prediction.slices[i - 1].physics.angular_velocity prev_normalized_ang_vel = normalize( vec3(prev_ang_vel.x, prev_ang_vel.y, prev_ang_vel.z)) current_ang_vel = ball_prediction.slices[ i].physics.angular_velocity current_normalized_ang_vel = normalize( vec3(current_ang_vel.x, current_ang_vel.y, current_ang_vel.z)) if prev_normalized_ang_vel != current_normalized_ang_vel and location[ 2] < 125: self.bounces.append((location, i * 1 / 60)) def set_mechanics(self): if self.drive is None: self.drive = Drive(self.info.my_car, self.info.ball.pos, 1399) if self.catching is None: self.catching = Catching(self.info.my_car, self.info.ball.pos, 1399) if self.recovery is None: self.recovery = AerialTurn(self.info.my_car) if self.dodge is None: self.dodge = AirDodge(self.info.my_car, 0.25, self.info.ball.pos) if self.dribble is None: self.dribble = Dribbling(self.info.my_car, self.info.ball, self.info.their_goal) def get_controls(self): if self.step == "Steer" or self.step == "Dodge2": self.step = "Catching" if self.step == "Catching": target = get_bounce(self) if target is None: self.step = "Defending" else: self.catching.target_pos = target[0] self.catching.target_speed = (distance_2d( self.info.my_car.pos, target[0]) + 50) / target[1] self.catching.step(self.FPS) self.controls = self.catching.controls ball = self.info.ball car = self.info.my_car if distance_2d(ball.pos, car.pos) < 150 and 65 < abs(ball.pos[2] - car.pos[2]) < 127: self.step = "Dribbling" self.dribble = Dribbling(self.info.my_car, self.info.ball, self.info.their_goal) if self.defending: self.step = "Defending" if not self.info.my_car.on_ground: self.step = "Recovery" ball = self.info.ball if abs(ball.vel[2]) < 100 and sign( self.team) * ball.vel[1] < 0 and sign( self.team) * ball.pos[1] < 0: self.step = "Shooting" elif self.step == "Dribbling": self.dribble.step(self.FPS) self.controls = self.dribble.controls ball = self.info.ball car = self.info.my_car bot_to_opponent = self.info.opponents[0].pos - self.info.my_car.pos local_bot_to_target = dot(bot_to_opponent, self.info.my_car.theta) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) opponent_is_near = norm(vec2(bot_to_opponent)) < 2000 opponent_is_in_the_way = math.radians( -10) < angle_front_to_target < math.radians(10) if not (distance_2d(ball.pos, car.pos) < 150 and 65 < abs(ball.pos[2] - car.pos[2]) < 127): self.step = "Catching" if self.defending: self.step = "Defending" if opponent_is_near and opponent_is_in_the_way: self.step = "Dodge" self.dodge = AirDodge(self.info.my_car, 0.25, self.info.their_goal.center) if not self.info.my_car.on_ground: self.step = "Recovery" elif self.step == "Defending": defending(self) elif self.step == "Dodge": self.dodge.step(self.FPS) self.controls = self.dodge.controls self.controls.boost = 0 if self.dodge.finished and self.info.my_car.on_ground: self.step = "Catching" elif self.step == "Recovery": self.recovery.step(self.FPS) self.controls = self.recovery.controls if self.info.my_car.on_ground: self.step = "Catching" elif self.step == "Shooting": shooting(self) def render_string(self, string): self.renderer.begin_rendering('The State') if self.step == "Dodge1": self.renderer.draw_line_3d(self.info.my_car.pos, self.dodge.target, self.renderer.black()) self.renderer.draw_line_3d(self.info.my_car.pos, self.bounces[0][0], self.renderer.blue()) self.renderer.draw_string_2d( 20, 20, 3, 3, string + " " + str(abs(self.info.ball.vel[2])) + " " + str(sign(self.team) * self.info.ball.vel[1]), self.renderer.red()) self.renderer.end_rendering() def should_defending(self): ball = self.info.ball car = self.info.my_car our_goal = self.info.my_goal.center car_to_ball = ball.pos - car.pos in_front_of_ball = distance_2d(ball.pos, our_goal) < distance_2d( car.pos, our_goal) backline_intersect = line_backline_intersect( self.info.my_goal.center[1], vec2(car.pos), vec2(car_to_ball)) return in_front_of_ball and abs(backline_intersect) < 2000
class BoostHog(BaseAgent): def initialize_agent(self): self.info = GameInfo(self.index, self.team, self.get_field_info()) self.controls = SimpleControllerState() self.phase = None self.targets = [] self.guides = [] self.active_pads = [] self.plan_pads = [] #plans a path using a bezier curve def pathplan(self): car = self.info.my_car k = 50 #number of guides on path p0_ = car.pos p1_ = car.pos + car.vel * 2 #compensation for velocity self.guides = [] if len(self.targets) == 1: p2_ = self.targets[0] for i in range(k): self.guides.append(bezier(p0_, p1_, p2_, p2_, (i / k))) else: p2_ = self.targets[0] + normalize( self.targets[0] - self.targets[1] ) * 100 #number not final, adjusts curve so that car ends up facing next target p3_ = self.targets[0] for i in range(k): self.guides.append(bezier(p0_, p1_, p2_, p3_, (i / k))) #find any convenient boost along path and adds it as a target def convboost(self): for guide in self.guides: for pad in self.active_pads: if pad not in self.plan_pads and norm( guide - pad.pos ) <= 300: #number not final, distance from guide to potential convenient boost has to be less or equal to this number self.plan_pads.append(pad) self.targets.insert(0, pad.pos) self.pathplan() self.convboost() break else: continue break def turn_radius(self): # https://docs.google.com/spreadsheets/d/1Hhg1TJqVUCcKIRmwvO2KHnRZG1z8K4Qn-UnAf5-Pt64/edit?usp=sharing car_speed = norm(self.info.my_car.vel) return (+156 + 0.1 * car_speed + 0.000069 * car_speed**2 + 0.000000164 * car_speed**3 - 5.62 * 10**(-11) * car_speed**4) def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) if self.phase == None: self.phase = 1 #phase 1: path-planning elif self.phase == 1: self.targets = [vec3(0, 0, 25)] #TODO pick targets self.pathplan() #adds all active boost pads to this list, big boosts first self.active_pads = [] for pad in self.info.boost_pads: if pad.is_active: self.active_pads.append(pad) for pad in self.info.small_boost_pads: if pad.is_active: self.active_pads.append(pad) self.plan_pads = [] self.convboost() #elif self.phase == 2: #TODO follow path #debug prints if True: self.renderer.begin_rendering("debug") self.renderer.draw_string_2d(20, 20, 1, 1, "phase: " + str(self.phase), self.renderer.black()) self.renderer.draw_string_2d(20, 40, 1, 1, "targets: " + str(len(self.targets)), self.renderer.black()) self.renderer.draw_string_2d(20, 60, 1, 1, "guides: " + str(len(self.guides)), self.renderer.black()) self.renderer.draw_string_2d( 20, 80, 1, 1, "big pads: " + str(len(self.info.boost_pads)), self.renderer.black()) self.renderer.draw_string_2d( 20, 100, 1, 1, "small pads: " + str(len(self.info.small_boost_pads)), self.renderer.black()) self.renderer.draw_string_2d( 20, 120, 1, 1, "active pads: " + str(len(self.active_pads)), self.renderer.black()) self.renderer.draw_string_2d( 20, 140, 1, 1, "turn radius: " + str(self.turn_radius()), self.renderer.black()) self.renderer.draw_string_2d(20, 160, 1, 1, "car direction: " + "test", self.renderer.black()) self.renderer.end_rendering() #renders targets for i in range(len(self.targets)): self.renderer.begin_rendering("target" + str(i)) render_target(self, self.targets[i]) self.renderer.end_rendering() #renders path self.renderer.begin_rendering("path") self.renderer.draw_polyline_3d(self.guides, self.renderer.white()) self.renderer.end_rendering() return self.controls