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 initialize_hive(self, packet: GameTickPacket) -> None: index = next(iter(self.drone_indices)) self.team = packet.game_cars[index].team self.info = GameInfo(self.team) self.info.set_mode("soccar") self.strategy = HivemindStrategy(self.info, self.logger) self.draw = DrawingTool(self.renderer, self.team) self.drones = [Drone(self.info.cars[i], i) for i in self.drone_indices] self.logger.handlers[0].setLevel( logging.NOTSET) # override handler level self.logger.setLevel(logging.INFO if RELEASE else logging.DEBUG) self.logger.info("Beehive initialized")
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)
class Beehive(PythonHivemind): def __init__(self, *args): super().__init__(*args) self.info: GameInfo = None self.team: int = None self.draw: DrawingTool = None self.drones: List[Drone] = [] self.strategy: HivemindStrategy = None self.last_latest_touch_time = 0.0 def initialize_hive(self, packet: GameTickPacket) -> None: index = next(iter(self.drone_indices)) self.team = packet.game_cars[index].team self.info = GameInfo(self.team) self.info.set_mode("soccar") self.strategy = HivemindStrategy(self.info, self.logger) self.draw = DrawingTool(self.renderer, self.team) self.drones = [Drone(self.info.cars[i], i) for i in self.drone_indices] self.logger.handlers[0].setLevel( logging.NOTSET) # override handler level self.logger.setLevel(logging.INFO if RELEASE else logging.DEBUG) self.logger.info("Beehive initialized") def get_outputs(self, packet: GameTickPacket) -> Dict[int, PlayerInput]: self.info.read_packet(packet, self.get_field_info()) # if a kickoff is happening and none of the drones have a Kickoff maneuver active, reset all drone maneuvers if (packet.game_info.is_kickoff_pause and self.info.ball.position[0] == 0 and self.info.ball.position[1] == 0 and not any( isinstance(drone.maneuver, Kickoff) for drone in self.drones)): if len(self.drones) == 1: self.drones[0].maneuver = None else: self.strategy.set_kickoff_maneuvers(self.drones) # reset drone maneuvers when an opponent hits the ball touch = packet.game_ball.latest_touch if touch.time_seconds > self.last_latest_touch_time and touch.team != self.team: self.last_latest_touch_time = touch.time_seconds for drone in self.drones: if drone.maneuver and drone.maneuver.interruptible( ): # don't reset a drone while dodging/recovering drone.maneuver = None # reset drone maneuver when it gets demoed for drone in self.drones: if drone.maneuver and drone.car.demolished: drone.maneuver = None # if at least one drone doesn't have an active maneuver, execute strategy code if None in [drone.maneuver for drone in self.drones]: self.logger.debug("Setting maneuvers") if len(self.drones) == 1: self.drones[0].maneuver = teamplay_strategy.choose_maneuver( self.info, self.drones[0].car) else: self.strategy.set_maneuvers(self.drones) for drone in self.drones: if drone.maneuver is None: continue # execute maneuvers drone.maneuver.step(self.info.time_delta) drone.controls = drone.maneuver.controls drone.maneuver.render(self.draw) # draw names of maneuvers above our drones self.draw.color(self.draw.yellow) self.draw.string(drone.car.position + vec3(0, 0, 50), type(drone.maneuver).__name__) # expire finished maneuvers if drone.maneuver.finished: drone.maneuver = None if len(self.drones) > 1: self.strategy.avoid_demos_and_team_bumps(self.drones) self.strategy.render(self.draw) self.draw.execute() return {drone.index: drone.get_player_input() for drone in self.drones}
def initialize_agent(self): self.info = GameInfo(self.team) self.info.set_mode("soccar") self.draw = DrawingTool(self.renderer, self.team)
class BotimusPrime(BaseAgent): RENDERING = True def __init__(self, name, team, index): super().__init__(name, team, index) self.info: GameInfo = None self.draw: DrawingTool = None self.tick_counter = 0 self.last_latest_touch_time = 0 self.maneuver: Optional[Maneuver] = None self.controls: SimpleControllerState = SimpleControllerState() def initialize_agent(self): self.info = GameInfo(self.team) self.info.set_mode("soccar") self.draw = DrawingTool(self.renderer, self.team) def get_output(self, packet: GameTickPacket): # wait a few ticks after initialization, so we work correctly in rlbottraining if self.tick_counter < 20: self.tick_counter += 1 return Input() self.info.read_packet(packet, self.get_field_info()) # cancel maneuver if a kickoff is happening and current maneuver isn't a kickoff maneuver if packet.game_info.is_kickoff_pause and not isinstance( self.maneuver, Kickoff): self.maneuver = None # reset maneuver when another car hits the ball touch = packet.game_ball.latest_touch if (touch.time_seconds > self.last_latest_touch_time and touch.player_name != packet.game_cars[self.index].name): self.last_latest_touch_time = touch.time_seconds # don't reset when we're dodging, wavedashing or recovering if self.maneuver and self.maneuver.interruptible(): self.maneuver = None # choose maneuver if self.maneuver is None: if self.RENDERING: self.draw.clear() if self.info.get_teammates(self.info.cars[self.index]): self.maneuver = teamplay_strategy.choose_maneuver( self.info, self.info.cars[self.index]) else: self.maneuver = solo_strategy.choose_maneuver( self.info, self.info.cars[self.index]) # execute maneuver if self.maneuver is not None: self.maneuver.step(self.info.time_delta) self.controls = self.maneuver.controls if self.RENDERING: self.draw.group("maneuver") self.draw.color(self.draw.yellow) self.draw.string( self.info.cars[self.index].position + vec3(0, 0, 50), type(self.maneuver).__name__) self.maneuver.render(self.draw) # cancel maneuver when finished if self.maneuver.finished: self.maneuver = None if self.RENDERING: self.draw.execute() return self.controls
def is_opponent_close(info: GameInfo, dist: float) -> bool: for opponent in info.get_opponents(): if ground_distance(opponent.position + opponent.velocity * 0.5, info.ball) < dist: return True return False