Ejemplo n.º 1
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
Ejemplo n.º 2
0
    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 = kickoffs.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

        self.defending_drone = max(
            drones,
            key=lambda drone: ground_distance(drone.car, self.info.ball))
        self.defending_drone.maneuver = DriveBackwardsToGoal(
            self.defending_drone.car, self.info)

        for drone in drones:
            if drone not in corner_drones + [self.defending_drone
                                             ] + [self.drone_going_for_ball]:
                self.send_drone_for_boost(drone)
Ejemplo n.º 3
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 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
Ejemplo n.º 4
0
def direct_shot(info: GameInfo, car: Car, target: vec3) -> Strike:
    dodge_shot = DodgeStrike(car, info, target)
    ground_shot = GroundStrike(car, info, target)

    if car.boost > 40:  # TODO
        # aerial_strike = AerialStrike(car, info, target)
        fast_aerial = FastAerialStrike(car, info, target)

        better_aerial_strike = min([fast_aerial],
                                   key=lambda strike: strike.intercept.time)

        if (better_aerial_strike.intercept.time < dodge_shot.intercept.time
                and abs(better_aerial_strike.intercept.position[1] -
                        info.their_goal.center[1]) > 500):
            if ground_distance(better_aerial_strike.intercept,
                               info.their_goal.center) < 8000:
                return DoubleTouch(better_aerial_strike)
            return better_aerial_strike

    if (dodge_shot.intercept.time < ground_shot.intercept.time - 0.1
            or ground_distance(dodge_shot.intercept, target) < 2000 or
            distance(ground_shot.intercept.ball.velocity, car.velocity) < 500
            or is_opponent_close(info, 300)):
        if (distance(dodge_shot.intercept.ground_pos, target) < 4000
                and abs(dodge_shot.intercept.ground_pos[0]) < 2000):
            return CloseShot(car, info, target)
        return dodge_shot
    return ground_shot
Ejemplo n.º 5
0
    def direct_shot(self, car: Car, target: vec3) -> Maneuver:
        dodge_shot = DodgeStrike(car, self.info, target)
        ground_shot = GroundStrike(car, self.info, target)

        if car.boost > 40:  # TODO
            aerial_strike = AerialStrike(car, self.info, target)
            fast_aerial = FastAerialStrike(car, self.info, target)

            better_aerial_strike = min(
                [aerial_strike, fast_aerial],
                key=lambda strike: strike.intercept.time)

            if better_aerial_strike.intercept.time < dodge_shot.intercept.time:
                if ground_distance(better_aerial_strike.intercept,
                                   self.info.their_goal.center) < 5000:
                    return DoubleTouch(better_aerial_strike)
                return better_aerial_strike

        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
Ejemplo n.º 6
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 (or tied) to the ball, go for kickoff
        if distance(my_car, ball) == min(distance(car, ball) for car in my_team):
            return kickoffs.choose_kickoff(info, my_car)

    if my_car.boost < 20:
        best_boostpad = choose_boostpad_to_pickup(info, my_car)
        if best_boostpad is not None:
            return PickupBoostPad(my_car, best_boostpad)

    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 ground_distance(my_car, my_goal) < 2000:
            best_intercept = my_intercept

    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)
Ejemplo n.º 7
0
    def step(self, dt):
        target = self.target
        car = self.car

        if self.target_direction is not None:
            car_speed = norm(car.velocity)
            target_direction = normalize(self.target_direction)

            # in order to arrive in a direction, we need to shift the target in the opposite direction
            # the magnitude of the shift is based on how far are we from the target
            shift = clamp(
                ground_distance(car.position, target) * self.lerp_t, 0,
                car_speed * 1.5)

            # if we're too close to the target, aim for the actual target so we don't miss it
            if shift - self.additional_shift < Drive.turn_radius(
                    clamp(car_speed, 1400, 2000) * 1.1):
                shift = 0
            else:
                shift += self.additional_shift

            shifted_target = target - target_direction * shift

            time_shift = ground_distance(shifted_target, target) * 0.7 / clamp(
                car_speed, 500, 2300)
            shifted_arrival_time = self.arrival_time - time_shift

        else:
            shifted_target = target
            shifted_arrival_time = self.arrival_time

        self.drive.target_pos = shifted_target
        self.travel.target = shifted_target

        dist_to_target = ground_distance(car.position, shifted_target)
        time_left = nonzero(shifted_arrival_time - car.time)
        target_speed = clamp(dist_to_target / time_left, 0, 2300)
        self.drive.target_speed = target_speed
        self.drive.backwards = self.backwards

        # dodges and wavedashes can mess up correctly arriving, so we use them only if we really need them
        if ((self.allow_dodges_and_wavedashes
             and norm(car.velocity) < target_speed - 600 and car.boost < 20
             and not self.backwards)
                or not self.travel.driving  # a dodge/wavedash is in progress
            ):
            self.action = self.travel
        else:
            self.action = self.drive

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

        self.finished = self.car.time >= self.arrival_time
Ejemplo n.º 8
0
    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) < 100
                    and dot(car.forward(), dir_to_target) > 0.7
                    and norm(car.velocity) > clamp(
                        distance(car, self.target) / 3, 1000, 1700)
                    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():
                if (distance(opponent.position + opponent.velocity, car) < max(
                        300.0,
                        norm(opponent.velocity) * 0.5)
                        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.target = self.info.ball.position + self.info.ball.velocity * 0.2
            self.flick.step(dt)
            self.controls = self.flick.controls
            self.finished = self.flick.finished
Ejemplo n.º 9
0
    def step(self, dt: float):
        car = self.car
        if self.phase == 1:
            if norm(car.velocity) > 800:
                self.action = SpeedFlip(
                    car,
                    right_handed=local(car, self.info.ball.position)[1] < 0)
                self.phase = 2
                self._speed_flip_start_time = car.time

        if self.phase == 2:
            if self.action.finished and self.car.on_ground:
                self.action = self.drive
                self.drive.target_pos = vec3(0, 0, 0)
                self.phase = 3

        if self.phase == 3:
            if ground_distance(self.car, vec3(0, 0, 0)) < 500:
                self.action = AirDodge(car, 0.1, vec3(0, 0, 0))
                self.phase = 4

        if self.phase == 4:
            if self.action.finished:
                self.finished = True

        # abort when taking too long
        if car.time > self._speed_flip_start_time + 3.0: self.finished = True

        super().step(dt)
Ejemplo n.º 10
0
def estimate_time(car: Car, target, dd=1) -> float:
    turning_radius = 1 / Drive.max_turning_curvature(norm(car.velocity) + 500)
    turning = angle_between(car.forward() * dd, direction(
        car, target)) * turning_radius / 1800
    if turning < 0.5: turning = 0

    dist = ground_distance(car, target) - 200
    if dist < 0: return turning
    speed = dot(car.velocity, car.forward())

    time = 0
    result = None
    if car.boost > 0 and dd > 0:
        boost_time = car.boost / 33.33
        result = BOOST.simulate_until_limit(speed,
                                            distance_limit=dist,
                                            time_limit=boost_time)
        dist -= result.distance_traveled
        time += result.time_passed
        speed = result.speed_reached

    if dist > 0 and speed < 1410:
        result = THROTTLE.simulate_until_limit(speed, distance_limit=dist)
        dist -= result.distance_traveled
        time += result.time_passed
        speed = result.speed_reached

    if result is None or not result.distance_limit_reached:
        time += dist / speed

    return time * 1.05 + turning
Ejemplo n.º 11
0
    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, 40, 60)

        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
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
    def step(self, dt):
        if self.jumping:
            self.controls = Input()
            # first jump for full 0.2 sec
            if self.timer <= 0.2:
                self.controls.jump = True
            # single tick between jumps
            elif self.timer <= 0.2 + dt * JUMP_FALSE_TICKS:
                self.controls.jump = False
            # second jump
            else:
                self.controls.jump = True
                self.jumping = False
            self.timer += dt

        else:
            self.finished = self.intercept.time < self.info.time

            if self.car.on_ground:
                # manage speed before jump
                distance_to_target = ground_distance(self.car.position,
                                                     self.intercept.position)
                if distance_to_target < MIN_DIST_BEFORE_SPEED_CONTROL:
                    target_speed = distance_to_target / self.time_for_jump
                    self.drive.target_speed = -target_speed if self._should_strike_backwards else target_speed
                    self.drive.step(dt)
                    self.controls = self.drive.controls

                else:
                    super().step(dt)

                # decide when to jump
                ground_vel = ground(self.car.velocity)
                direction_to_target = ground_direction(self.car.position,
                                                       self.intercept.position)
                alignment = dot(normalize(ground_vel), direction_to_target)
                # check alignment
                if alignment >= MIN_ALIGNMENT:
                    # check that speed is correct
                    speed_in_direction = dot(ground_vel, direction_to_target)
                    time_to_target = distance_to_target / speed_in_direction
                    if self.time_for_jump - ALLOWED_TIME_ERROR <= time_to_target <= self.time_for_jump + ALLOWED_TIME_ERROR:
                        self.jumping = True

            # after jump (when the car is in the air)
            else:
                # face the ball for some additional height
                self.reorient.target_orientation = look_at(
                    direction(self.car.position, self.info.ball),
                    vec3(0, 0, 1))
                self.reorient.step(dt)
                self.controls = self.reorient.controls
Ejemplo n.º 14
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
Ejemplo n.º 15
0
    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
        if self.car.boost < 100 and ground_distance(self.car,
                                                    self.travel.target) < 4000:
            self.controls.boost = False

        self.finished = self.travel.driving and self.car.time > self.start_time + self.DURATION
Ejemplo n.º 16
0
    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 and abs(
                self.car.position.x) < 1000:
            target = Arena.clamp(target, 200)
            target[0] = abs_clamp(target[0], 700)

        if not self.drive_on_walls:
            seam_radius = 100 if abs(
                self.car.position[1]) > Arena.size[1] - 100 else 200
            if self.car.position[2] > seam_radius:
                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(3.0 * phi)

        # powersliding
        self.controls.handbrake = 0
        if (abs(phi) > 1.5 and self.car.position[2] < 300
                and (ground_distance(self.car, target) < 3500
                     or abs(self.car.position[0]) > 3500) and
                dot(normalize(self.car.velocity), self.car.forward()) > 0.85):
            self.controls.handbrake = 1

        # 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
            elif (vf - self.target_speed) > 100:
                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:
            self.controls.boost = 0

        # finish when close
        if distance(self.car, self.target_pos) < 100:
            self.finished = True
Ejemplo n.º 17
0
    def step(self, dt):
        car = self.car
        target = ground(self.target)

        car_speed = norm(car.velocity)
        time_left = (ground_distance(car, target) - self.finish_distance) / max(car_speed + 500, 1400)
        forward_speed = dot(car.forward(), car.velocity)

        if self.driving and car.on_ground:
            self.action.target_pos = target
            self._time_on_ground += dt

            # check if it's a good idea to dodge, wavedash or halfflip
            if (
                self._time_on_ground > 0.2
                and car.position[2] < 200
                and car_speed < 2000
                and angle_to(car, target, backwards=forward_speed < 0) < 0.1
                and car.gravity[2] < -500  # don't dodge in low gravity
            ):
                # if going forward, use a dodge or a wavedash
                if forward_speed > 0:
                    use_boost_instead = self.waste_boost and car.boost > 20

                    if car_speed > 1200 and not use_boost_instead:
                        if time_left > self.DODGE_DURATION:
                            dodge = Dodge(car)
                            dodge.duration = 0.07
                            dodge.direction = vec2(direction(car, target))
                            self.action = dodge
                            self.driving = False

                        elif time_left > self.WAVEDASH_DURATION:
                            wavedash = Wavedash(car)
                            wavedash.direction = vec2(direction(car, target))
                            self.action = wavedash
                            self.driving = False

                # if going backwards, use a halfflip
                elif time_left > self.HALFFLIP_DURATION and car_speed > 800:
                    self.action = HalfFlip(car, self.waste_boost and time_left > 3)
                    self.driving = False

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

        # make sure we're not boosting airborne
        if self.driving and not car.on_ground:
            self.controls.boost = False

        # make sure we're not stuck turtling
        if not car.on_ground:
            self.controls.throttle = 1

        # a dodge/wavedash/halfflip has finished
        if self.action.finished and not self.driving:
            self.driving = True
            self._time_on_ground = 0
            self.action = self.drive
            self.drive.backwards = False

        if ground_distance(car, target) < self.finish_distance and self.driving:
            self.finished = True
Ejemplo n.º 18
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)
Ejemplo n.º 19
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)
Ejemplo n.º 20
0
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
Ejemplo n.º 21
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)
Ejemplo n.º 22
0
    def step(self, dt: float):
        self.drive.step(dt)
        self.controls = self.drive.controls

        if ground_distance(self.car, self.drive.target_pos) < 100:
            self.finished = True
Ejemplo n.º 23
0
    def step(self, dt):
        time_left = self.aerial.arrival_time - self.car.time

        if self.aerialing:
            to_ball = direction(self.car, self.info.ball)

            # freestyling
            if self.car.position[2] > 200:
                # if time_left > 0.7:
                #     rotation = axis_to_rotation(self.car.forward() * 0.5)
                #     self.aerial.up = dot(rotation, self.car.up())
                # else:
                self.aerial.up = vec3(0, 0, -1) + xy(to_ball)

            self.aerial.target_orientation = look_at(to_ball,
                                                     vec3(0, 0, -3) + to_ball)
            self.aerial.step(dt)

            self.controls = self.aerial.controls
            self.finished = self.aerial.finished and time_left < -0.3

        else:
            super().step(dt)

            # simulate aerial from current state
            simulated_car = self.simulate_flight(self.car, self.aerial,
                                                 self._flight_path)

            speed_towards_target = dot(
                self.car.velocity,
                ground_direction(self.car, self.aerial.target_position))
            speed_needed = ground_distance(
                self.car, self.aerial.target_position) / time_left

            # too fast, slow down
            if speed_towards_target > speed_needed and angle_to(
                    self.car, self.aerial.target_position) < 0.1:
                self.controls.throttle = -1

            # if it ended up near the target, we could take off
            elif distance(
                    simulated_car,
                    self.aerial.target_position) < self.MAX_DISTANCE_ERROR:
                if angle_to(self.car,
                            self.aerial.target_position) < 0.1 or norm(
                                self.car.velocity) < 1000:

                    if self.DELAY_TAKEOFF and ground_distance(
                            self.car, self.aerial.target_position) > 1000:
                        # extrapolate current state a small amount of time
                        future_car = Car(self.car)
                        time = 0.5
                        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, self.aerial)

                        # 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_position) > 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
Ejemplo n.º 24
0
 def is_opponent_close(self, car, ball) -> bool:
     for opponent in self.info.get_opponents(car):
         if ground_distance(opponent, ball) < ball.position[2] * 2 + 1000:
             return True
     return False