Example #1
0
    def __init__(self, car: Car, info: GameInfo, face_target: vec3,
                 distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.face_target = face_target

        dist = min(distance_from_target,
                   ground_distance(face_target, self.info.my_goal.center) - 50)
        target_pos = ground(face_target) + ground_direction(
            face_target, self.info.my_goal.center) * dist

        near_goal = ground_distance(car, info.my_goal.center) < 3000
        side_shift = 400 if near_goal else 2000
        points = [
            target_pos + vec3(side_shift, 0, 0),
            target_pos - vec3(side_shift, 0, 0)
        ]
        target_pos = nearest_point(face_target,
                                   points) if near_goal else furthest_point(
                                       face_target, points)

        self.target = Arena.clamp(target_pos, 500)

        self.travel = Travel(car, self.target)
        self.travel.finish_distance = 800 if near_goal else 1500
        self.drive = Drive(car)

        self.start_time = car.time
        self.wait = Stop(car)
Example #2
0
class ShadowDefense(Maneuver):

    DURATION = 0.5

    def __init__(self, car: Car, info: GameInfo, face_target: vec3, distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.face_target = face_target

        dist = min(distance_from_target, ground_distance(face_target, self.info.my_goal.center) - 50)
        target_pos = ground(face_target) + ground_direction(face_target, self.info.my_goal.center) * dist

        near_goal = ground_distance(car, info.my_goal.center) < 3000
        side_shift = 400 if near_goal else 2000
        points = [target_pos + vec3(side_shift, 0, 0), target_pos - vec3(side_shift, 0, 0)]
        target_pos = nearest_point(face_target, points) if near_goal else farthest_point(face_target, points)
        target_pos = Arena.clamp(target_pos, 500)

        self.travel = Travel(car, target_pos)
        self.travel.finish_distance = 800 if near_goal else 1500
        self.drive = Drive(car)
        self.drive.target_speed = 1000
        self.stop = Stop(car)

        self.start_time = car.time

    def interruptible(self) -> bool:
        return self.travel.interruptible()

    def step(self, dt):
        self.travel.step(dt)
        self.controls = self.travel.controls

        if ground_distance(self.car, self.travel.target) < 3000:
            self.controls.boost = False

        if self.travel.finished:
            if angle_to(self.car, self.face_target) > 0.3:
                self.drive.target_pos = self.face_target
                self.drive.step(dt)
                self.controls = self.drive.controls
                self.controls.handbrake = False
            else:
                self.stop.step(dt)
                self.controls = self.stop.controls

        self.controls.boost = False

        self.finished = self.travel.driving and self.car.time > self.start_time + self.DURATION

    def render(self, draw: DrawingTool):
        self.travel.render(draw)
Example #3
0
class ShadowDefense(Maneuver):

    def __init__(self, car: Car, info: GameInfo, target: vec3, distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.target = target

        ball = info.ball
        dist = min(distance_from_target, ground_distance(target, self.info.my_goal.center) - 50)
        target_pos = ground(target) + ground_direction(target, self.info.my_goal.center) * dist

        side_shift = distance_from_target / 4 if ground_distance(car, info.my_goal.center) > 2500 else 400
        points = [target_pos + vec3(side_shift, 0, 0), target_pos - vec3(side_shift, 0, 0)]
        target_pos = nearest_point(car.pos, points)

        self.target = Arena.clamp(target_pos, 700)

        self.travel = Travel(car, self.target)
        self.drive = Drive(car)

        self.start_time = car.time
        self.wait = Stop(car)

    def step(self, dt):
        ball = self.info.ball

        if (
            distance(self.car, ball) < 1000
            and align(self.car.pos, ball, self.info.my_goal.center) > 0.2
        ):
            shift = normalize(cross(direction(ball, self.car), vec3(0, 0, 1))) * 1000
            self.travel.target = nearest_point(self.car.pos, [ball.pos + shift, ball.pos - shift])
        else:
            self.travel.target = self.target

        self.travel.step(dt)
        self.controls = self.travel.controls
        if self.travel.finished:
            if angle_to(self.car, self.target) > 0.2 and norm(self.car.vel) < 600:
                self.drive.target_pos = self.target
                self.drive.step(dt)
                self.drive.target_speed = 500
                self.drive.controls.handbrake = False
                self.controls = self.drive.controls
            else:
                self.wait.step(dt)
                self.controls = self.wait.controls
        self.finished = self.travel._driving and self.car.time > self.start_time + 0.5

    def render(self, draw: DrawingTool):
        self.travel.render(draw)
Example #4
0
    def __init__(self, car: Car, info: GameInfo, target: vec3, distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.target = target

        ball = info.ball
        dist = min(distance_from_target, ground_distance(target, self.info.my_goal.center) - 50)
        target_pos = ground(target) + ground_direction(target, self.info.my_goal.center) * dist

        side_shift = distance_from_target / 4 if ground_distance(car, info.my_goal.center) > 2500 else 400
        points = [target_pos + vec3(side_shift, 0, 0), target_pos - vec3(side_shift, 0, 0)]
        target_pos = nearest_point(car.pos, points)

        self.target = Arena.clamp(target_pos, 700)

        self.travel = Travel(car, self.target)
        self.drive = Drive(car)

        self.start_time = car.time
        self.wait = Stop(car)
Example #5
0
    def __init__(self,
                 car: Car,
                 info: GameInfo,
                 face_target: vec3,
                 distance_from_target: float,
                 force_nearest=False):
        super().__init__(car)

        self.info = info
        self.face_target = face_target

        dist = min(distance_from_target,
                   ground_distance(face_target, self.info.my_goal.center) - 50)
        target_pos = ground(face_target) + ground_direction(
            face_target, self.info.my_goal.center) * dist

        near_goal = abs(car.position[1] - info.my_goal.center[1]) < 3000
        side_shift = 400 if near_goal else 1800
        points = target_pos + vec3(side_shift, 0, 0), target_pos - vec3(
            side_shift, 0, 0)
        if abs(self.car.position.x) > 3000:
            force_nearest = True
        target_pos = nearest_point(
            face_target,
            points) if near_goal or force_nearest else farthest_point(
                face_target, points)
        if abs(face_target[0]) < 1000 or ground_distance(car,
                                                         face_target) < 1000:
            target_pos = nearest_point(car.position, points)
        target_pos = Arena.clamp(target_pos, 500)

        self.travel = Travel(car, target_pos)
        self.travel.finish_distance = 800 if near_goal else 1500
        self.drive = Drive(car)
        self.stop = Stop(car)

        self.start_time = car.time

        self.pad = None
Example #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)
Example #7
0
class ShadowDefense(Maneuver):
    def __init__(self, car: Car, info: GameInfo, face_target: vec3,
                 distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.face_target = face_target

        dist = min(distance_from_target,
                   ground_distance(face_target, self.info.my_goal.center) - 50)
        target_pos = ground(face_target) + ground_direction(
            face_target, self.info.my_goal.center) * dist

        near_goal = ground_distance(car, info.my_goal.center) < 3000
        side_shift = 400 if near_goal else 2000
        points = [
            target_pos + vec3(side_shift, 0, 0),
            target_pos - vec3(side_shift, 0, 0)
        ]
        target_pos = nearest_point(face_target,
                                   points) if near_goal else furthest_point(
                                       face_target, points)

        self.target = Arena.clamp(target_pos, 500)

        self.travel = Travel(car, self.target)
        self.travel.finish_distance = 800 if near_goal else 1500
        self.drive = Drive(car)

        self.start_time = car.time
        self.wait = Stop(car)

    def step(self, dt):
        ball = self.info.ball

        # if (
        #     distance(self.car, ball) < 1000
        #     and align(self.car.position, ball, self.info.my_goal.center) > 0.2
        # ):
        #     shift = normalize(cross(direction(ball, self.car), vec3(0, 0, 1))) * 1000
        #     self.travel.target = nearest_point(self.car.position, [ball.position + shift, ball.position - shift])
        # else:
        #     self.travel.target = self.target

        self.travel.step(dt)
        self.controls = self.travel.controls

        if ground_distance(self.car, self.travel.target) < 3000:
            self.controls.boost = False

        if self.travel.finished:
            if angle_to(self.car, self.face_target) > 0.3:
                self.drive.target_pos = self.face_target
                self.drive.step(dt)
                self.drive.target_speed = 700
                self.drive.controls.handbrake = False
                self.controls = self.drive.controls
            else:
                self.wait.step(dt)
                self.controls = self.wait.controls
        self.finished = self.travel.driving and self.car.time > self.start_time + 0.5

    def render(self, draw: DrawingTool):
        self.travel.render(draw)
Example #8
0
    def choose_maneuver(self):
        info = self.info
        offense = self.offense

        ball = info.ball
        car = info.my_car

        my_score, their_score = self.get_team_scores()

        their_goal = ground(info.their_goal.center)
        my_goal = ground(info.my_goal.center)

        my_hit = Intercept(car, info.ball_predictions)
        their_best_hit, opponent = self.best_intercept(info.opponents, 500)

        if my_score > their_score + 2:
            self.aggresivity = 5
        else:
            self.aggresivity = 0

        if their_score > my_score:
            if self.packet.game_info.game_time_remaining < 60:
                self.aggresivity = 5
            if self.packet.game_info.game_time_remaining < 30:
                self.aggresivity = 30

        should_commit = True
        if info.teammates:
            best_team_intercept, _ = self.best_intercept(info.teammates, 500)
            if best_team_intercept.time < my_hit.time - 0.05:
                should_commit = False

        if not car.on_ground:
            return self.when_airborne()

        # kickoff
        if should_commit and ball.pos[0] == 0 and ball.pos[1] == 0:
            return Kickoff(car, info)

        # dont 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.pos, my_hit.ball, their_goal) > -0.2:

                any_shot = offense.any_shot(car, their_goal, my_hit)

                if (not isinstance(any_shot, Strike) or their_best_hit.time < any_shot.intercept.time + 0.5) \
                and align(car.pos, my_hit.ball, their_goal) < 0.6:

                    return DodgeStrike(car, info, their_goal)
                return any_shot

            return self.clear_into_corner(my_hit)

        # fallback
        if align(car.pos, my_hit.ball, my_goal) > 0.2:
            if ground_distance(my_hit,
                               my_goal) < 4000 and should_commit and abs(
                                   car.pos[1]) < abs(my_hit.pos[1]):
                return self.clear_into_corner(my_hit)
            return ShadowDefense(car, info, my_hit.ground_pos, 6000)

        # clear
        if (should_commit and ground_distance(my_hit, my_goal) < 3500
                and abs(my_hit.pos[0]) < 3000
                and ground_distance(car, my_goal) < 2500):

            if align(car.pos, my_hit.ball, their_goal) > -0.1:

                any_shot = offense.any_shot(car, their_goal, my_hit)

                if (not isinstance(any_shot, Strike) or their_best_hit.time < any_shot.intercept.time + 0.5) \
                and align(car.pos, my_hit.ball, their_goal) < 0.6:

                    return DodgeStrike(car, info, their_goal)
                return any_shot
            return self.clear_into_corner(my_hit)

        # double tap
        if should_commit and car.pos[2] > 1000:
            double_tap = offense.double_tap(car, their_goal)
            if double_tap is not None:
                return double_tap

        # 1v1
        if not info.teammates:
            if distance(their_best_hit.ground_pos, their_goal) < distance(
                    their_best_hit.ground_pos, my_goal):
                opponents_align = -align(opponent.pos, their_best_hit.ball,
                                         their_goal)
            else:
                opponents_align = align(opponent.pos, their_best_hit.ball,
                                        my_goal)

            # I can get to ball faster than them
            if should_commit and 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.pos[1] -
                           their_goal[1]) > 300 or ground_distance(
                               strike.intercept, their_goal) < 900:
                        return strike

            # they are out of position
            if (should_commit
                    and opponents_align < -0.1 - self.aggresivity / 20 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.pos[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.pos[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.pos, 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.pos, 1400) < 1.5:
                    return refuel

        # teamplay
        else:
            if should_commit:
                return offense.any_shot(car, their_goal, my_hit)

            if car.boost < 50:
                return Refuel(car, info, my_goal)

        shadow_distance = 5500
        shadow_distance -= self.aggresivity * 500
        shadow_distance = max(shadow_distance, 3000)
        return ShadowDefense(car, info, their_best_hit.ground_pos,
                             shadow_distance)
Example #9
0
class GeneralDefense(Maneuver):
    """
    First, attempt to rotate on the far side, and when far away enough from the target (usually the ball),
    turn around to face it. If already far enough and facing the target, just stop and wait.
    Also try to pickup boost pads along the way.
    This state expires after a short amount of time, so we can look if there's something better to do. If not,
    it can be simply instantiated again.
    """

    DURATION = 0.5

    BOOST_LOOK_RADIUS = 1200
    BOOST_LOOK_ANGLE = 0.5

    def __init__(self, car: Car, info: GameInfo, face_target: vec3,
                 distance_from_target: float):
        super().__init__(car)

        self.info = info
        self.face_target = face_target

        dist = min(distance_from_target,
                   ground_distance(face_target, self.info.my_goal.center) - 50)
        target_pos = ground(face_target) + ground_direction(
            face_target, self.info.my_goal.center) * dist

        near_goal = ground_distance(car, info.my_goal.center) < 3000
        side_shift = 400 if near_goal else 2500
        points = [
            target_pos + vec3(side_shift, 0, 0),
            target_pos - vec3(side_shift, 0, 0)
        ]
        target_pos = nearest_point(face_target,
                                   points) if near_goal else farthest_point(
                                       face_target, points)
        target_pos = Arena.clamp(target_pos, 500)

        self.travel = Travel(car, target_pos)
        self.travel.finish_distance = 800 if near_goal else 1500
        self.drive = Drive(car)
        self.stop = Stop(car)

        self.start_time = car.time

        self.pad = None

    def interruptible(self) -> bool:
        return self.travel.interruptible()

    def step(self, dt):
        # update finished state even if we are not using the controls
        self.travel.step(dt)

        if self.travel.finished:
            # turn around to face the target direction
            if angle_to(self.car, self.face_target) > 0.3:
                self.drive.target_pos = self.face_target
                self.drive.target_speed = 1000
                self.drive.step(dt)
                self.controls = self.drive.controls
                self.controls.handbrake = False
            else:
                self.stop.step(dt)
                self.controls = self.stop.controls

        else:
            self.pad = None

            # collect boost pads on the way (greedy algorithm, assumes first found is best)
            if self.car.boost < 90 and self.travel.interruptible():
                to_target = ground_direction(self.car, self.travel.target)

                for pad in self.info.large_boost_pads + self.info.small_boost_pads:
                    to_pad = ground_direction(self.car, pad)

                    if (pad.is_active and
                            distance(self.car, pad) < self.BOOST_LOOK_RADIUS
                            and angle_between(to_target,
                                              to_pad) < self.BOOST_LOOK_ANGLE):
                        self.pad = pad
                        self.drive.target_pos = pad.position
                        self.drive.target_speed = 2200
                        self.drive.step(dt)
                        self.controls = self.drive.controls
                        break

            # go to the actual target
            if self.pad is None:
                self.controls = self.travel.controls

        # don't waste boost during downtime
        self.controls.boost = False

        self.finished = self.travel.driving and self.car.time > self.start_time + self.DURATION

    def render(self, draw: DrawingTool):
        self.travel.render(draw)

        # render target pad
        if self.pad:
            draw.color(draw.blue)
            draw.circle(self.pad.position, 50)