def step(self, dt): if not self.flicking: self.carry.step(dt) self.controls = self.carry.controls self.finished = self.carry.finished car = self.car ball = self.info.ball # check if it's a good idea to flick dir_to_target = ground_direction(car, self.target) if ( distance(car, ball) < 150 and ground_distance(car, ball) < 80 and dot(car.forward(), dir_to_target) > 0.7 and norm(car.velocity) > distance(car, self.target) / 3 and norm(car.velocity) > 1300 and dot(dir_to_target, ground_direction(car, ball)) > 0.9 ): self.flicking = True # flick if opponent is close for opponent in self.info.get_opponents(car): if ( distance(opponent.position + opponent.velocity, car) < max(300.0, norm(opponent.velocity)) and dot(opponent.velocity, direction(opponent, self.info.ball)) > 0.5 ): if distance(car.position, self.info.ball.position) < 200: self.flicking = True else: self.finished = True else: self.flick.step(dt) self.controls = self.flick.controls self.finished = self.flick.finished
def step(self, dt): if self.aerialing: self.aerial.target_orientation = look_at( direction(self.car, self.target), vec3(0, 0, -1)) self.aerial.step(dt) self.controls = self.aerial.controls self.finished = self.aerial.finished else: super().step(dt) # simulate aerial from current state simulated_car = self.simulate_flight(self.car) # if the car ended up too far, we're too fast and we need to slow down if ground_distance(self.car, self.aerial.target) + 100 < ground_distance( self.car, simulated_car): # self.controls.throttle = -1 pass # if it ended up near the target, we could take off elif distance(simulated_car, self.aerial.target) < self.MAX_DISTANCE_ERROR: if angle_to(self.car, self.aerial.target) < 0.1 or norm( self.car.velocity) < 1000: if self.DELAY_TAKEOFF: # extrapolate current state a small amount of time future_car = Car(self.car) time = 0.2 future_car.time += time displacement = future_car.velocity * time if norm(future_car.velocity) > 500\ else normalize(future_car.velocity) * 500 * time future_car.position += displacement # simulate aerial fot the extrapolated car again future_simulated_car = self.simulate_flight( future_car, write_to_flight_path=False) # if the aerial is also successful, that means we should continue driving instead of taking off # this makes sure that we go for the most late possible aerials, which are the most effective if distance( future_simulated_car, self.aerial.target) > self.MAX_DISTANCE_ERROR: self.aerialing = True else: self.too_early = True else: self.aerialing = True else: # self.controls.boost = True self.controls.throttle = 1
def step(self, dt): car = self.car if self.phase == 1: if norm(car.velocity) > 1400: self.phase = 2 self.action = AirDodge(car, 0.05, car.position + car.velocity) if self.phase == 2: self.action.controls.boost = self.action.state_timer < 0.1 if car.on_ground and self.action.finished: self.action = self.drive self.phase = 3 if self.phase == 3: if distance(car, vec3(0, 0, 93)) < norm(car.velocity) * 0.4: self.phase = 4 self.action = AirDodge(car, 0.05, self.info.ball.position) self.counter_fake_kickoff() if self.phase == 4: if self.action.finished: self.finished = True super().step(dt)
def counter_fake_kickoff(self): if any( distance(self.info.ball, opponent) < 1500 for opponent in self.info.get_opponents(self.car)): return self.phase = "anti-fake-kickoff" self.action = self.drive
def estimate_time(car: Car, target, speed, dd=1) -> float: dist = distance(car, target) if dist < 100: return 0 travel = dist / speed turning = angle_between(car.forward() * dd, direction(car, target)) / math.pi * 2 if turning < 1: turning **= 2 acceleration = (speed * dd - dot(car.velocity, car.forward())) / 2100 * 0.2 * dd / max(car.boost / 20, 1) return travel + acceleration + turning * 0.7
def step(self, dt): if self.pad is None: self.finished = True return # slow down when we're about to pick up the boost, so we can turn faster afterwards if distance(self.car, self.pad) < norm(self.car.velocity) * 0.2: self.travel.drive.target_speed = 1400 self.travel.step(dt) self.controls = self.travel.controls # finish when someone picks up the pad if not self.pad.is_active and self.pad_was_active: self.finished = True self.pad_was_active = self.pad.is_active # finish when we picked the boost up but the previous condition somehow wasn't true if self.car.boost > 99 or distance(self.car, self.pad) < 100: self.finished = True
def direct_shot(self, car: Car, target: vec3) -> Maneuver: dodge_shot = DodgeShot(car, self.info, target) ground_shot = GroundShot(car, self.info, target) if car.boost > 40: aerial_strike = AerialStrike(car, self.info, target) fast_aerial = FastAerialStrike(car, self.info, target) if min(aerial_strike.intercept.time, fast_aerial.intercept.time) < dodge_shot.intercept.time: return min([aerial_strike, fast_aerial], key=lambda strike: strike.intercept.time) if (dodge_shot.intercept.time < ground_shot.intercept.time - 0.1 or ground_distance(dodge_shot.intercept, target) < 4000 or distance(ground_shot.intercept.ball.velocity, car.velocity) < 500): if (distance(dodge_shot.intercept.ground_pos, target) < 4000 and abs(dodge_shot.intercept.ground_pos[0]) < 3000): return CloseShot(car, self.info, target) return dodge_shot return ground_shot
def __init__(self, car: Car, target: vec3 = vec3(0, 0, 0), waste_boost=False): super().__init__(car) self.target = Arena.clamp(ground(target), 100) self.waste_boost = waste_boost self.finish_distance = 500 self._time_on_ground = 0 self.driving = True # decide whether to start driving backwards and halfflip later forward_estimate = estimate_time(car, self.target, estimate_max_car_speed(car)) backwards_estimate = estimate_time(car, self.target, 1400, -1) + 0.5 backwards = (backwards_estimate < forward_estimate and (distance(car, self.target) > 3000 or distance(car, self.target) < 300) and car.position[2] < 200) self.drive = Drive(car, self.target, 2300, backwards) self.action = self.drive
def best_boostpad_to_pickup(car: Car, pads: Set[Pad], pos: vec3) -> Pad: best_pad = None best_dist = math.inf for pad in pads: dist = distance(pos, pad.position) time_estimate = estimate_time(car, pad.position, estimate_max_car_speed(car)) if dist < best_dist and (pad.is_active or pad.timer < time_estimate): best_pad = pad best_dist = dist return best_pad
def set_kickoff_maneuvers(self, drones: List[Drone]): nearest_drone = min(drones, key=lambda drone: ground_distance(drone.car, self.info.ball)) nearest_drone.maneuver = KickoffStrategy.choose_kickoff(self.info, nearest_drone.car) self.drone_going_for_ball = nearest_drone self.boost_reservations.clear() corner_drones = [drone for drone in drones if abs(drone.car.position[0]) > 2000] if len(corner_drones) > 1: other_corner_drone = next(drone for drone in corner_drones if drone is not nearest_drone) nearest_pad = min(self.info.large_boost_pads, key=lambda pad: distance(other_corner_drone.car, pad)) other_corner_drone.maneuver = HalfFlipPickup(other_corner_drone.car, nearest_pad) self.boost_reservations[other_corner_drone] = nearest_pad for drone in drones: if drone is not nearest_drone and drone not in corner_drones: reserved_pads = {self.boost_reservations[d] for d in self.boost_reservations} drone.maneuver = Refuel(drone.car, self.info, self.info.my_goal.center, forbidden_pads=reserved_pads) self.boost_reservations[drone] = drone.maneuver.pad
def step(self, dt): ball = Ball(self.ball) car = self.car # simulate ball until it gets near the floor while (ball.position[2] > 120 or ball.velocity[2] > 0) and ball.time < car.time + 10: ball.step(1 / 60) ball_local = local(car, ground(ball.position)) target = local(car, self.target) shift = ground(direction(ball_local, target)) shift[1] *= 1.8 shift = normalize(shift) max_turn = clamp(norm(car.velocity) / 800, 0, 1) max_shift = normalize(vec3(1 - max_turn, max_turn * sign(shift[1]), 0)) if abs(shift[1]) > abs(max_shift[1]) or shift[0] < 0: shift = max_shift shift *= clamp(car.boost, 30, 50) shift[1] *= clamp(norm(car.velocity) / 1000, 1, 2) self._shift_direction = normalize(world(car, shift) - car.position) target = world(car, ball_local - shift) speed = distance(car.position, target) / max(0.001, ball.time - car.time) self.drive.target_speed = speed self.drive.target_pos = target self.drive.step(dt) self.controls = self.drive.controls self.finished = self.ball.position[2] < 100 or ground_distance( self.ball, self.car) > 2000
def get_output(self, packet: GameTickPacket): self.time = packet.game_info.seconds_elapsed dt = self.time - self.prev_time if packet.game_info.is_kickoff_pause and not isinstance(self.maneuver, Kickoff): self.maneuver = None self.prev_time = self.time if self.ticks < 6: self.ticks += 1 self.info.read_packet(packet) self.strategy.packet = packet #reset maneuver when another car hits the ball touch = packet.game_ball.latest_touch if (( touch.time_seconds > self.last_touch_time and touch.player_name != packet.game_cars[self.index].name ) or ( touch.player_name == '' and # if latest touch info is missing any([distance(self.info.ball, car) < 300 for car in self.info.opponents + self.info.teammates]) )): self.last_touch_time = touch.time_seconds if ( self.info.my_car.on_ground and (not isinstance(self.maneuver, ShadowDefense) or self.maneuver.travel._driving) ): self.maneuver = None #self.reset_time = self.time # choose maneuver if self.maneuver is None and self.time > self.reset_time + 0.01 and self.ticks > 5: if self.RENDERING: self.draw.clear() self.info.predict_ball(self.PREDICTION_RATE * self.PREDITION_DURATION, 1 / self.PREDICTION_RATE) self.maneuver = self.strategy.choose_maneuver() name = str(type(self.maneuver).__name__) self.last_ball_vel = norm(self.info.ball.vel) # execute maneuver if self.maneuver is not None: self.maneuver.step(dt) # I have to convert from RLU Input to SimpleControllerState, because Input doesnt have 'use_item' self.controls.steer = self.maneuver.controls.steer self.controls.throttle = self.maneuver.controls.throttle self.controls.jump = self.maneuver.controls.jump self.controls.pitch = self.maneuver.controls.pitch self.controls.yaw = self.maneuver.controls.yaw self.controls.roll = self.maneuver.controls.roll self.controls.handbrake = self.maneuver.controls.handbrake self.controls.boost = self.maneuver.controls.boost if self.RENDERING: self.maneuver.render(self.draw) if self.maneuver.finished: self.maneuver = None if self.RENDERING: self.draw.execute() self.maybe_chat(packet) self.chat.step(packet) return self.controls
def maybe_chat(self, packet: GameTickPacket): chat = self.chat for team in packet.teams: if team.team_index == self.team: our_score = team.score else: their_score = team.score # last second goal if their_score > self.num_of_their_goals_reacted_to or our_score > self.num_of_our_goals_reacted_to: if abs(their_score - our_score) < 2 and packet.game_info.game_time_remaining < 5: for _ in range(6): self.chat.send_random([ chat.Reactions_OMG, chat.PostGame_Gg, chat.Reactions_HolyCow, chat.Reactions_NoWay, chat.Reactions_Wow, chat.Reactions_OMG ]) # they scored if their_score > self.num_of_their_goals_reacted_to: self.num_of_their_goals_reacted_to = their_score for _ in range(2): if self.last_ball_vel > 2000: self.chat.send_random([ chat.Compliments_NiceShot, chat.Compliments_NiceOne, chat.Reactions_Wow, chat.Reactions_OMG, chat.Reactions_Noooo ]) else: self.chat.send_random([ chat.Reactions_Whew, chat.Apologies_Whoops, chat.Apologies_Oops, chat.Apologies_Cursing ]) # we scored if our_score > self.num_of_our_goals_reacted_to: self.num_of_our_goals_reacted_to = our_score if self.last_ball_vel > 3000: self.chat.send(chat.Reactions_Siiiick) if self.last_ball_vel < 300: self.chat.send(chat.Compliments_WhatASave) # game is over if packet.game_info.is_match_ended and not self.said_gg: self.said_gg = True self.chat.send(chat.PostGame_Gg) self.chat.send(chat.PostGame_WellPlayed) if our_score < their_score: self.chat.send(chat.PostGame_OneMoreGame) # all yours :D if self.time > self.last_time_said_all_yours + 40: if isinstance(self.maneuver, ShadowDefense) and distance(self.info.my_car, self.info.ball) > 6000: self.last_time_said_all_yours = self.time self.chat.send(chat.Information_AllYours)
def step(self, dt): target = self.target_pos # don't try driving outside the arena target = Arena.clamp(target, 100) # smoothly escape goal if abs(self.car.position[1]) > Arena.size[1] - 50: target = Arena.clamp(target, 200) target[0] = abs_clamp(target[0], 700) if not self.drive_on_walls: if self.car.position[2] > 100: target = ground(self.car) local_target = local(self.car, target) if self.backwards: local_target[0] *= -1 local_target[1] *= -1 # steering phi = math.atan2(local_target[1], local_target[0]) self.controls.steer = clamp11(2.5 * phi) # powersliding if abs(phi) > 1.5 and self.car.position[2] < 200 and ground_distance( self.car, target) < 2500: self.controls.handbrake = 1 else: self.controls.handbrake = 0 # forward velocity vf = dot(self.car.velocity, self.car.forward()) if self.backwards: vf *= -1 # speed controller if vf < self.target_speed: self.controls.throttle = 1.0 if self.target_speed > 1400 and vf < 2250 and self.target_speed - vf > 50: self.controls.boost = 1 else: self.controls.boost = 0 else: if (vf - self.target_speed) > 400: # 75 self.controls.throttle = -1.0 else: if self.car.up()[2] > 0.85: self.controls.throttle = 0.0 else: self.controls.throttle = 0.01 self.controls.boost = 0 # backwards driving if self.backwards: self.controls.throttle *= -1 self.controls.steer *= -1 self.controls.boost = 0 self.controls.handbrake = 0 # don't boost if not facing target if abs(phi) > 0.3 and vf > 600: self.controls.boost = 0 # finish when close if distance(self.car, self.target_pos) < 100: self.finished = True
def get_output(self, packet: GameTickPacket): self.time = packet.game_info.seconds_elapsed dt = self.time - self.prev_time if packet.game_info.is_kickoff_pause and not isinstance( self.maneuver, Kickoff): self.maneuver = None self.prev_time = self.time self.ticks += 1 self.info.read_packet(packet, self.get_field_info()) self.strategy.packet = packet if self.ticks < 10: return Input() #reset maneuver when another car hits the ball touch = packet.game_ball.latest_touch if ((touch.time_seconds > self.last_touch_time and touch.player_name != packet.game_cars[self.index].name) or (touch.player_name == '' and # if latest touch info is missing any([ distance(self.info.ball, car) < 300 for car in self.info.opponents + self.info.teammates ]))): self.last_touch_time = touch.time_seconds if (self.info.my_car.on_ground and not self.controls.jump and (not isinstance(self.maneuver, ShadowDefense) or self.maneuver.travel.driving)): self.maneuver = None #self.reset_time = self.time if self.handle_training_matchcomms(): self.info.predict_ball( self.PREDICTION_RATE * self.PREDITION_DURATION, 1 / self.PREDICTION_RATE) self.maneuver = get_maneuver_by_name(self.matchcomms_message, self.info) print("Training: Setting " + self.matchcomms_message) # choose maneuver if self.maneuver is None: if self.RENDERING: self.draw.clear() self.info.predict_ball( self.PREDICTION_RATE * self.PREDITION_DURATION, 1 / self.PREDICTION_RATE) self.maneuver = self.strategy.choose_maneuver() name = str(type(self.maneuver).__name__) print(name) self.last_ball_vel = norm(self.info.ball.velocity) # execute maneuver if self.maneuver is not None: self.maneuver.step(dt) self.controls = self.maneuver.controls if self.RENDERING: self.draw.group("maneuver") self.maneuver.render(self.draw) if self.maneuver.finished: self.maneuver = None for pad in self.info.large_boost_pads: self.draw.string(pad.position, str(pad.is_full_boost)) if self.RENDERING: self.draw.execute() self.maybe_chat(packet) self.chat.step(packet) return self.controls
def choose_maneuver(self, car: Car): info = self.info offense = self.offense ball = info.ball teammates = info.get_teammates(car) opponents = info.get_opponents(car) their_goal = ground(info.their_goal.center) my_goal = ground(info.my_goal.center) my_hit = Intercept(car, info.ball_predictions) their_best_hit = self.best_intercept(opponents) opponent = their_best_hit.car # recovery if not car.on_ground: return Recovery(car) # kickoff should_go = all( distance(mate, ball) > distance(car, ball) for mate in teammates) if should_go and ball.position[0] == 0 and ball.position[1] == 0: return KickoffStrategy.choose_kickoff(info, car) # don't save our own shots if info.about_to_score: if info.time_of_goal < their_best_hit.time - 2: return Stop(car) # save if info.about_to_be_scored_on: if align(car.position, my_hit.ball, their_goal) > 0.0: return offense.direct_shot(car, their_goal) return ClearIntoCorner(car, info) # fallback if align(car.position, my_hit.ball, my_goal) > 0.2: if (ground_distance(my_hit, my_goal) < 4000 and abs(car.position[1]) < abs(my_hit.position[1])): return ClearIntoCorner(car, info) return ShadowDefense(car, info, my_hit.ground_pos, 6000) # clear if (ground_distance(my_hit, my_goal) < 3500 and abs(my_hit.position[0]) < 3000 and ground_distance(car, my_goal) < 2500): if align(car.position, my_hit.ball, their_goal) > 0: return offense.direct_shot(car, their_goal) return ClearIntoCorner(car, info) if distance(their_best_hit, their_goal) < distance( their_best_hit, my_goal): opponents_align = -align(opponent.position, their_best_hit.ball, their_goal) else: opponents_align = align(opponent.position, their_best_hit.ball, my_goal) # 1v1 if not teammates: # I can get to ball faster than them if my_hit.time < their_best_hit.time - 0.8: strike = offense.any_shot(car, their_goal, my_hit) if not isinstance(strike, Strike): return strike if strike.intercept.time < their_best_hit.time - 0.8 \ and (not info.about_to_score or strike.intercept.time < info.time_of_goal - 1): if strike.intercept.time - car.time > 4 and car.boost < 30 \ and distance(strike.intercept.ground_pos, their_goal) > 3000 and distance(their_best_hit.ground_pos, my_goal) > 5000: return Refuel(car, info, my_hit.ground_pos) if abs(strike.intercept.ground_pos[0] ) > Arena.size[0] - 800 and car.boost < 30: return Refuel(car, info, my_hit.ground_pos) if abs(strike.intercept.ball.position[1] - their_goal[1]) > 300 or ground_distance( strike.intercept, their_goal) < 900: return strike # they are out of position if (opponents_align < -0.1 and my_hit.time < their_best_hit.time - opponents_align * 1.5): strike = offense.any_shot(car, their_goal, my_hit) if not isinstance(strike, Strike) or strike.intercept.is_viable \ and (not info.about_to_score or strike.intercept.time < info.time_of_goal - 0.5): if (car.boost < 40 and (distance(my_hit, their_goal) > 5000 or abs(my_hit.position[0]) > Arena.size[0] - 1500) and distance(opponent, their_best_hit) > 3000): return Refuel(car, info, my_hit.ground_pos) if not isinstance(strike, Strike) or abs( strike.intercept.ball.position[1] - their_goal[1]) > 300 or ground_distance( strike.intercept, their_goal) < 900: return strike if distance(their_best_hit.ball, my_goal) > 7000 and \ (distance(their_best_hit, opponent) > 3000 or align(opponent.position, their_best_hit.ball, my_goal) < 0) and car.boost < 30: return Refuel(car, info, my_hit.ground_pos) if car.boost < 35 and distance(their_best_hit, opponent) > 3000: refuel = Refuel(car, info, my_hit.ground_pos) if estimate_time(car, refuel.pad.position, 1400) < 1.5: return refuel if opponents_align < 0: return offense.any_shot(car, their_goal, my_hit) # teamplay else: if car.boost < 40: return Refuel(car, info, my_goal) else: return offense.any_shot(car, their_goal, my_hit) shadow_distance = 4000 + opponents_align * 1500 shadow_distance = max(shadow_distance, 3000) return ShadowDefense(car, info, their_best_hit.ground_pos, shadow_distance)