def choose_maneuver(info: GameInfo, my_car: Car): ball = info.ball teammates = info.get_teammates(my_car) my_team = [my_car] + teammates their_goal = ground(info.their_goal.center) my_goal = ground(info.my_goal.center) # recovery if not my_car.on_ground: return Recovery(my_car) # kickoff if ball.position[0] == 0 and ball.position[1] == 0: # if I'm nearest to the ball, go for kickoff if min(my_team, key=lambda car: distance(car, ball)) is my_car: return kickoffs.choose_kickoff(info, my_car) if my_car.boost < 20: return Refuel(my_car, info) info.predict_ball() my_intercept = Intercept(my_car, info.ball_predictions) teammates_intercepts = [ Intercept(mate, info.ball_predictions) for mate in teammates ] our_intercepts = teammates_intercepts + [my_intercept] good_intercepts = [ i for i in our_intercepts if align(i.car.position, i.ball, their_goal) > 0.0 ] if good_intercepts: best_intercept = min(good_intercepts, key=lambda intercept: intercept.time) else: best_intercept = min(our_intercepts, key=lambda i: distance(i.car, my_goal)) if best_intercept is my_intercept: # if not completely out of position, go for a shot if (align(my_intercept.car.position, my_intercept.ball, their_goal) > 0 or ground_distance(my_intercept, my_goal) > 6000): return offense.any_shot(info, my_intercept.car, their_goal, my_intercept) # otherwise try to clear else: return defense.any_clear(info, my_intercept.car) # if I'm nearest to goal, stay far back if min(my_team, key=lambda car: distance(car, my_goal)) is my_car: return GeneralDefense(my_car, info, my_intercept.position, 7000) # otherwise get into position return GeneralDefense(my_car, info, my_intercept.position, 4000)
def any_shot(info: GameInfo, car: Car, target: vec3, intercept: Intercept, allow_dribble=False) -> Maneuver: ball = intercept.ball if (allow_dribble and (ball.position[2] > 100 or abs(ball.velocity[2]) > 250 or distance(car, info.ball) < 300) and abs(ball.velocity[2]) < 700 and ground_distance(car, ball) < 1500 and ground_distance(ball, info.my_goal.center) > 1000 and ground_distance(ball, info.their_goal.center) > 1000 and not is_opponent_close(info, info.ball.position[2] * 2 + 1000)): return CarryAndFlick(car, info, target) direct = direct_shot(info, car, target) if not isinstance(direct, GroundStrike) and intercept.time < car.time + 4.0: alignment = align(car.position, ball, target) if alignment < -0.3 and abs(ball.position[1] - target[1]) > 3000: return MirrorStrike(car, info, target) return direct
def any_shot(self, car: Car, target: vec3, intercept: Intercept) -> Maneuver: ball = intercept.ball if (self.allow_dribbles and (100 < ball.position[2] or abs(ball.velocity[2]) > 300) and abs(ball.velocity[2]) < 1500 and ground_distance(car, ball) < 1500 and ground_distance(ball, self.info.my_goal.center) > 1000): if not self.is_opponent_close(car, ball): return CarryAndFlick(car, self.info, target) alignment = align(car.position, ball, target) if alignment < 0.1 and abs(ball.position[1] - target[1]) > 3000: return MirrorStrike(car, self.info, target) # if 250 < ball.position[2] < 550 and self.is_opponent_close(car, ball): # return DoubleJumpStrike(car, self.info, target) return self.direct_shot(car, target)
def choose_maneuver(info: GameInfo, my_car: Car): ball = info.ball their_goal = ground(info.their_goal.center) my_goal = ground(info.my_goal.center) opponents = info.get_opponents() # recovery if not my_car.on_ground: return Recovery(my_car) # kickoff if ball.position[0] == 0 and ball.position[1] == 0: return kickoffs.choose_kickoff(info, my_car) info.predict_ball() my_intercept = Intercept(my_car, info.ball_predictions) their_intercepts = [ Intercept(opponent, info.ball_predictions) for opponent in opponents ] their_intercept = min(their_intercepts, key=lambda i: i.time) opponent = their_intercept.car banned_boostpads = { pad for pad in info.large_boost_pads if abs(pad.position[1] - their_goal[1]) < abs(my_intercept.position[1] - their_goal[1]) or abs(pad.position[0] - my_car.position[0]) > 6000 } # if ball is in a dangerous position, clear it if (ground_distance(my_intercept, my_goal) < 3000 and (abs(my_intercept.position[0]) < 2000 or abs(my_intercept.position[1]) < 4500) and my_car.position[2] < 300): if align(my_car.position, my_intercept.ball, their_goal) > 0.5: return offense.any_shot(info, my_intercept.car, their_goal, my_intercept, allow_dribble=True) return defense.any_clear(info, my_intercept.car) # if I'm low on boost and the ball is not near my goal, go for boost if my_car.boost < 10 and ground_distance(my_intercept, their_goal) > 3000: refuel = Refuel(my_car, info, forbidden_pads=banned_boostpads) if refuel.pad: return refuel ball_in_their_half = abs(my_intercept.position[1] - their_goal[1]) < 3000 shadow_distance = 4000 if ball_in_their_half else 6000 # if they can hit the ball sooner than me and they aren't out of position, wait in defense if (their_intercept.time < my_intercept.time and align(opponent.position, their_intercept.ball, my_goal) > -0.1 + opponent.boost / 100 and ground_distance(opponent, their_intercept) > 300 and dot(opponent.velocity, ground_direction(their_intercept, my_goal)) > 0): return GeneralDefense(my_car, info, my_intercept.position, shadow_distance, force_nearest=ball_in_their_half) # if not completely out of position, go for a shot if (align(my_car.position, my_intercept.ball, their_goal) > -0.5 or ground_distance(my_intercept, their_goal) < 2000 or ground_distance(opponent, their_intercept) < 300): if my_car.position[2] < 300: shot = offense.any_shot(info, my_intercept.car, their_goal, my_intercept, allow_dribble=True) if (not isinstance(shot, Strike) or shot.intercept.time < their_intercept.time or abs(shot.intercept.position[0]) < 3500): return shot if my_car.boost < 30: refuel = Refuel(my_car, info, forbidden_pads=banned_boostpads) if refuel.pad: return refuel # fallback return GeneralDefense(my_car, info, my_intercept.position, shadow_distance, force_nearest=ball_in_their_half)
def set_maneuvers(self, drones: List[Drone]): info = self.info their_goal = ground(info.their_goal.center) our_goal = ground(info.my_goal.center) if self.drone_going_for_ball is not None and self.drone_going_for_ball.maneuver is None: self.drone_going_for_ball = None if self.defending_drone is not None and self.defending_drone.maneuver is None: self.defending_drone = None # recovery for drone in drones: if drone.maneuver is None and not drone.car.on_ground: drone.maneuver = Recovery(drone.car) # decide which drone is gonna commit if self.drone_going_for_ball is None: ready_drones = [ drone for drone in drones if not drone.car.demolished and ( drone.maneuver is None or drone.maneuver.interruptible()) and drone.car.position[2] < 300 ] if not ready_drones: return info.predict_ball() our_intercepts = [ Intercept(drone.car, info.ball_predictions) for drone in ready_drones ] good_intercepts = [ i for i in our_intercepts if align(i.car.position, i.ball, their_goal) > 0.3 and ground_distance(i.car, i) > 2000 ] if good_intercepts: best_intercept = min(good_intercepts, key=lambda intercept: intercept.time) else: best_intercept = min( our_intercepts, key=lambda i: ground_distance(i.car, our_goal)) # find out which drone does the intercept belong to self.drone_going_for_ball = next( drone for drone in ready_drones if drone.car == best_intercept.car) # if not completely out of position, go for a shot if (align(best_intercept.car.position, best_intercept.ball, their_goal) > 0 or ground_distance(best_intercept, our_goal) > 6000): strike = offense.any_shot(info, best_intercept.car, their_goal, best_intercept) else: # otherwise try to clear strike = defense.any_clear(info, best_intercept.car) self.drone_going_for_ball.maneuver = strike if self.drone_going_for_ball is self.defending_drone: self.defending_drone = None # clear expired boost reservations for drone in drones: if not isinstance( drone.maneuver, PickupBoostPad) and drone in self.boost_reservations: del self.boost_reservations[drone] # drones that need boost go for boost for drone in drones: if drone.maneuver is None: if drone.car.boost < 30: self.send_drone_for_boost(drone) # pick one drone that will stay far back unemployed_drones = [ drone for drone in drones if drone.maneuver is None ] if unemployed_drones and self.defending_drone is None: self.defending_drone = min( unemployed_drones, key=lambda d: ground_distance(d.car, info.my_goal.center)) self.defending_drone.maneuver = GeneralDefense( self.defending_drone.car, info, info.ball.position, 7000) unemployed_drones.remove(self.defending_drone) for drone in unemployed_drones: drone.maneuver = GeneralDefense(drone.car, info, info.ball.position, 4000)
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 self.defense.any_clear(car) # 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 self.defense.any_clear(car) return GeneralDefense(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 self.defense.any_clear(car) 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 GeneralDefense(car, info, their_best_hit.ground_pos, shadow_distance)