예제 #1
0
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)
예제 #2
0
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
예제 #3
0
    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)
예제 #4
0
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)
예제 #5
0
    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)
예제 #6
0
    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)