예제 #1
0
    def execute_running(self):
        super().execute_running()
        # abort if we can't see the ball
        if not main.ball().valid:
            return

        ball_pos = main.ball().pos

        self.intercept = (constants.Field.OurGoalSegment.center() -
                          main.ball().pos) * 0.25 + main.ball().pos

        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(ball_pos))

        # we build an array of OpponentRobots sorted rudimentarily by their threat
        # Right now, this is (inverse of) distance to the ball * 2 + y position.
        # Needs tuning/improvement. Right now this is excessively defensive
        sorted_opponents = sorted(
            filter(lambda robot: robot != their_kicker, main.their_robots()),
            key=lambda robot: self.calculate_shot_chance(robot),
            reverse=True)

        # Decide what each marking robot should do
        # @sorted_opponents contains the robots we want to mark by priority
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if i < len(sorted_opponents):
                mark_i.mark_robot = sorted_opponents[i]

        self.marks[2].mark_robot = their_kicker
        self.marks[2].mark_ratio = 0.5
예제 #2
0
    def execute_running(self):
        super().execute_running()
        # abort if we can't see the ball
        if not main.ball().valid:
            return

        ball_pos = main.ball().pos

        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(ball_pos))

        # we build an array of OpponentRobots sorted rudimentarily by their threat
        # Right now, this is (inverse of) distance to the ball * 2 + y position.
        # Needs tuning/improvement. Right now this is excessively defensive
        sorted_opponents = sorted(
            filter(lambda robot: robot != their_kicker, main.their_robots()),
            key=lambda robot: robot.pos.dist_to(ball_pos) * 2 + robot.pos.y)

        # Decide what each marking robot should do
        # @sorted_opponents contains the robots we want to mark by priority
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if i < len(sorted_opponents):
                mark_i.mark_robot = sorted_opponents[i]
예제 #3
0
    def execute_running(self):
        # abort if we can't see the ball
        if not main.ball().valid:
            return


        ball_pos = main.ball().pos


        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(), key=lambda opp: opp.pos.dist_to(ball_pos))


        # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples
        # we'll use these in a sec to assign our marking robots
        open_opps_and_dists = []
        for opp in main.their_robots():
            # ignore their kicker
            if opp == their_kicker: continue

            ball_dist = opp.pos.dist_to(ball_pos)

            # see if the opponent is close enough to the ball for us to care
            # if it is, we record the closest distance from one of our robots to it
            if ball_dist < 3.0:
                # which of our robots is closest to this opponent
                closest_self_dist = min([bot.pos.dist_to(opp.pos) for bot in main.our_robots()])
                open_opps_and_dists.append( (opp, closest_self_dist) )


        # Decide what each marking robot should do
        # @open_opps contains the robots we want to mark (if any)
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if mark_i.robot != None:
                if i < len(open_opps_and_dists):
                    # mark the opponent
                    mark_i.mark_robot = open_opps_and_dists[i][0]
                else:
                    pass
                    # NOTE: the old code ran these motion commands INSTEAD of running the mark command
                    # we could do that, but it'd require removing the subbehavior and re-adding a move or something...

                    # # move towards the ball and face it, but don't get within field center's radius
                    # pos = mark_i.robot.pos
                    # target = pos + (ball_pos - pos).normalized() * (ball_pos.dist_to(pos) - constants.Field.CenterRadius)
                    
                    # mark_i.robot.move(target)
                    # mark_i.face(ball_pos)


        # tell the marking robots to avoid eachother more than normal
        for i, mark_i in enumerate(self.marks):
            for j, mark_j in enumerate(self.marks):
                if i == j: continue
                if mark_i.robot != None and mark_j.robot != None:
                    mark_i.robot.set_avoid_teammate_radius(mark_j.robot.shell_id(), 0.5)
예제 #4
0
    def execute_running(self):
        super().execute_running()
        # abort if we can't see the ball
        if not main.ball().valid:
            return

        ball_pos = main.ball().pos

        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(ball_pos))

        # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples
        # we'll use these in a sec to assign our marking robots
        open_opps_and_dists = []
        for opp in main.their_robots():
            # ignore their kicker
            if opp == their_kicker: continue

            ball_dist = opp.pos.dist_to(ball_pos)

            # see if the opponent is close enough to the ball for us to care
            # if it is, we record the closest distance from one of our robots to it
            if ball_dist < 3.0:
                # which of our robots is closest to this opponent
                closest_self_dist = min(
                    [bot.pos.dist_to(opp.pos) for bot in main.our_robots()])
                open_opps_and_dists.append((opp, closest_self_dist))

        # Decide what each marking robot should do
        # @open_opps contains the robots we want to mark (if any)
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if mark_i.robot != None:
                if i < len(open_opps_and_dists):
                    # mark the opponent
                    mark_i.mark_robot = open_opps_and_dists[i][0]
                else:
                    pass
                    # NOTE: the old code ran these motion commands INSTEAD of running the mark command
                    # we could do that, but it'd require removing the subbehavior and re-adding a move or something...

                    # # move towards the ball and face it, but don't get within field center's radius
                    # pos = mark_i.robot.pos
                    # target = pos + (ball_pos - pos).normalized() * (ball_pos.dist_to(pos) - constants.Field.CenterRadius)

                    # mark_i.robot.move(target)
                    # mark_i.face(ball_pos)

                    # tell the marking robots to avoid eachother more than normal
        for i, mark_i in enumerate(self.marks):
            for j, mark_j in enumerate(self.marks):
                if i == j: continue
                if mark_i.robot != None and mark_j.robot != None:
                    mark_i.robot.set_avoid_teammate_radius(
                        mark_j.robot.shell_id(), 0.5)
예제 #5
0
def can_collect_ball_before_opponent(our_robots_to_check=None,
                                     their_robots_to_check=None,
                                     our_robots_to_dodge=None,
                                     their_robots_to_dodge=None,
                                     valid_error_percent=0.05):
    if our_robots_to_check is None:
        our_robots_to_check = main.our_robots()

    if their_robots_to_check is None:
        their_robots_to_check = main.their_robots()

    if our_robots_to_dodge is None:
        our_robots_to_dodge = main.our_robots()

    if their_robots_to_dodge is None:
        their_robots_to_dodge = main.their_robots()

    shortest_opp_time = float("inf")
    shortest_our_time = float("inf")
    dodge_dist = constants.Robot.Radius
    closest_robot = None

    # TODO: Do some sort of prediction as the ball moves
    target_pos = main.ball().pos

    # TODO: Take velocity and acceleration into account
    # Find closest opponent robot
    for bot in their_robots_to_check:
        dist = estimate_path_length(bot.pos, target_pos, our_robots_to_dodge,
                                    dodge_dist)
        target_dir = (target_pos - bot.pos).normalized()
        time = robocup.get_trapezoidal_time(
            dist, dist, 2.2, 1,
            target_dir.dot(bot.vel) / target_dir.mag(), 0)
        if (time < shortest_opp_time):
            shortest_opp_time = time

    # Find closest robot on our team
    for bot in our_robots_to_check:
        dist = estimate_path_length(bot.pos, target_pos, their_robots_to_dodge,
                                    dodge_dist)
        target_dir = (target_pos - bot.pos).normalized()
        time = robocup.get_trapezoidal_time(
            dist, dist, 2.2, 1,
            target_dir.dot(bot.vel) / target_dir.mag(), 0)
        if (time < shortest_our_time):
            shortest_our_time = time
            closest_robot = bot

    # Greater than 1 when we are further away
    print(shortest_our_time)
    print(shortest_opp_time)
    return shortest_our_time < shortest_opp_time * (
        1 + valid_error_percent), closest_robot
예제 #6
0
def can_collect_ball_before_opponent(our_robots_to_check=None,
                                     their_robots_to_check=None,
                                     our_robots_to_dodge=None,
                                     their_robots_to_dodge=None,
                                     valid_error_percent=0.05):
    if our_robots_to_check is None:
        our_robots_to_check = main.our_robots()

    if their_robots_to_check is None:
        their_robots_to_check = main.their_robots()

    if our_robots_to_dodge is None:
        our_robots_to_dodge = main.our_robots()

    if their_robots_to_dodge is None:
        their_robots_to_dodge = main.their_robots()

    shortest_opp_time = float("inf")
    shortest_our_time = float("inf")
    dodge_dist = constants.Robot.Radius
    closest_robot = None

    # TODO: Do some sort of prediction as the ball moves
    target_pos = main.ball().pos

    # TODO: Take velocity and acceleration into account
    # Find closest opponent robot
    for bot in their_robots_to_check:
        dist = estimate_path_length(bot.pos, target_pos, our_robots_to_dodge,
                                    dodge_dist)
        target_dir = (target_pos - bot.pos).normalized()
        time = robocup.get_trapezoidal_time(dist, dist, 2.2, 1,
                                            target_dir.dot(bot.vel) /
                                            target_dir.mag(), 0)
        if (time < shortest_opp_time):
            shortest_opp_time = time

    # Find closest robot on our team
    for bot in our_robots_to_check:
        dist = estimate_path_length(bot.pos, target_pos, their_robots_to_dodge,
                                    dodge_dist)
        target_dir = (target_pos - bot.pos).normalized()
        time = robocup.get_trapezoidal_time(dist, dist, 2.2, 1,
                                            target_dir.dot(bot.vel) /
                                            target_dir.mag(), 0)
        if (time < shortest_our_time):
            shortest_our_time = time
            closest_robot = bot

    return shortest_our_time < shortest_opp_time * (1 + valid_error_percent
                                                    ), closest_robot
예제 #7
0
def num_on_offense():
    # Complementary filter based on...
    #	Distance to their goal
    #	Distance to the ball
    goal_loc = robocup.Point(0, constants.Field.Length)
    corner_loc = robocup.Point(constants.Field.Width / 2, 0)
    ball_loc = main.ball().pos

    max_goal_dis = (goal_loc - corner_loc).mag()
    ball_to_goal = (goal_loc - ball_loc).mag()
    offense_ctr = 0

    filter_coeff = 0.7
    score_cutoff = .3

    # For each of their robots
    for bot in main.their_robots():
        if bot.visible:
            dist_to_ball = (bot.pos - ball_loc).mag()
            dist_to_goal = (bot.pos - goal_loc).mag()

            goal_coeff = dist_to_goal / max_goal_dis
            if ball_to_goal != 0:
                ball_coeff = 1 - (dist_to_ball / ball_to_goal)
            else:
                ball_coeff = 1
            ball_coeff = max(0, ball_coeff * ball_coeff)

            score = filter_coeff * goal_coeff + (1 - filter_coeff) * ball_coeff

            # Only count if their score is above the cutoff
            if (score > score_cutoff):
                offense_ctr += 1

    return offense_ctr
예제 #8
0
 def is_goalie_close(self):
     # if any of there robots are in near chip range chip over them
     close_check = False
     for r in main.their_robots():
         close_check = close_check or (
             r.pos - main.ball().pos).mag() < self.goalie_range
     return close_check
예제 #9
0
    def in_chip_distance(self):
        chipIndicator = False
        for r in main.their_robots():
            chipIndicator = chipIndicator or (
                r.pos - constants.Field.OurGoalSegment.nearest_point(
                    r.pos)).mag() < self.chip_distance

        return chipIndicator
예제 #10
0
    def other_robot_touching_ball(self):
        max_radius = constants.Robot.Radius + constants.Ball.Radius + 0.03
        for bot in list(main.our_robots()) + list(main.their_robots()):
            if bot.visible and (not bot.is_ours() or not bot.shell_id() == self.kicker_shell_id):
                if bot.pos.near_point(main.ball().pos, max_radius):
                    return True

        return False
예제 #11
0
    def other_robot_touching_ball(self):
        max_radius = constants.Robot.Radius + constants.Ball.Radius + 0.03
        for bot in list(main.our_robots()) + list(main.their_robots()):
            if bot.visible and (not bot.is_ours()
                                or not bot.shell_id() == self.kicker_shell_id):
                if bot.pos.near_point(main.ball().pos, max_radius):
                    return True

        return False
예제 #12
0
 def other_robot_touching_ball(self):
     for bot in filter(lambda bot: bot.visible,
                       list(main.our_robots()) + list(main.their_robots())):
         if (bot.is_ours() and bot.has_ball()
                 and bot.shell_id() != self.kicker_shell_id):
             return True
         if ((bot.shell_id() != self.kicker_shell_id or not bot.is_ours())
                 and self._bot_in_radius(bot)):
             return True
     return False
def find_defense_positions(ignore_robots=[]):

    their_risk_scores = []

    for bot in main.their_robots():
        score = estimate_risk_score(bot.pos, ignore_robots)
        main.system_state().draw_text("Risk: " + str(int(score * 100)),
                                      bot.pos, constants.Colors.White,
                                      "Defense")
        their_risk_scores.extend([score])

    # Sorts bot array based on their score
    zipped_array = zip(their_risk_scores, main.their_robots())
    sorted_array = sorted(zipped_array, reverse=True)
    sorted_bot = [bot for (scores, bot) in sorted_array]

    area_def_pos = create_area_defense_zones(ignore_robots)

    return area_def_pos, sorted_bot[0], sorted_bot[1]
def find_defense_positions(ignore_robots=[]):

    their_risk_scores = []

    for bot in main.their_robots():
        score = estimate_risk_score(bot.pos, ignore_robots)
        main.debug_drawer().draw_text("Risk: " + str(int(score * 100)),
                                      bot.pos, constants.Colors.White,
                                      "Defense")
        their_risk_scores.extend([score])

    # Sorts bot array based on their score
    zipped_array = zip(their_risk_scores, main.their_robots())
    sorted_array = sorted(zipped_array, reverse=True)
    sorted_bot = [bot for (scores, bot) in sorted_array]

    area_def_pos = create_area_defense_zones(ignore_robots)

    return area_def_pos, sorted_bot[0], sorted_bot[1]
예제 #15
0
 def other_robot_touching_ball(self):
     for bot in filter(lambda bot: bot.visible,
                       list(main.our_robots()) + list(main.their_robots())):
         if (bot.is_ours() and
             bot.has_ball() and
                 bot.shell_id() != self.kicker_shell_id):
             return True
         if ((bot.shell_id() != self.kicker_shell_id or
              not bot.is_ours()) and
                 self._bot_in_radius(bot)):
             return True
     return False
예제 #16
0
    def execute_setup_penalty(self):
        pt = robocup.Point(0, robocup.Field_PenaltyDist)
        penalty_kicker = min(main.their_robots(), key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(penalty_kicker.pos, penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = shot_line.intersection(Goalie.RobotSegment)
        if dest == None:
            self.robot.move_to(robocup.Point(0, constants.Robot.Radius))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.y = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
        self.robot.move_to(dest)
예제 #17
0
    def execute_running(self):
        super().execute_running()
        # abort if we can't see the ball
        if not main.ball().valid:
            return

        ball_pos = main.ball().pos

        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(ball_pos))

        # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples
        # we'll use these in a sec to assign our marking robots
        open_opps_and_dists = []
        for opp in main.their_robots():
            # ignore their kicker
            if opp == their_kicker: continue

            ball_dist = opp.pos.dist_to(ball_pos)

            # see if the opponent is close enough to the ball for us to care
            # if it is, we record the closest distance from one of our robots to it
            if ball_dist < 3.0:
                # which of our robots is closest to this opponent
                closest_self_dist = min(
                    [bot.pos.dist_to(opp.pos) for bot in main.our_robots()])
                open_opps_and_dists.append((opp, closest_self_dist))

        # Decide what each marking robot should do
        # @open_opps contains the robots we want to mark (if any)
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if mark_i.robot != None:
                if i < len(open_opps_and_dists):
                    # mark the opponent
                    mark_i.mark_robot = open_opps_and_dists[i][0]
                else:
                    pass
예제 #18
0
    def execute_running(self):
        super().execute_running()
        # abort if we can't see the ball
        if not main.ball().valid:
            return

        ball_pos = main.ball().pos

        # the closest of their bots to the ball is their kicker
        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(ball_pos))

        # we build an array of (OpponentRobot, float distToClosestOfOurBots) tuples
        # we'll use these in a sec to assign our marking robots
        open_opps_and_dists = []
        for opp in main.their_robots():
            # ignore their kicker
            if opp == their_kicker: continue

            ball_dist = opp.pos.dist_to(ball_pos)

            # see if the opponent is close enough to the ball for us to care
            # if it is, we record the closest distance from one of our robots to it
            if ball_dist < 3.0:
                # which of our robots is closest to this opponent
                closest_self_dist = min([bot.pos.dist_to(opp.pos)
                                         for bot in main.our_robots()])
                open_opps_and_dists.append((opp, closest_self_dist))

        # Decide what each marking robot should do
        # @open_opps contains the robots we want to mark (if any)
        # any robot that isn't assigned a mark_robot will move towards the ball
        for i, mark_i in enumerate(self.marks):
            if mark_i.robot != None:
                if i < len(open_opps_and_dists):
                    # mark the opponent
                    mark_i.mark_robot = open_opps_and_dists[i][0]
                else:
                    pass
예제 #19
0
    def __init__(self):
        super().__init__(continuous=True)

        self.debug = False

        self.add_transition(behavior.Behavior.State.start,
                            behavior.Behavior.State.running, lambda: True,
                            'immediately')

        self.marks = []

        if (main.game_state().is_their_direct()):
            self.intercept = (constants.Field.OurGoalSegment.center() -
                              main.ball().pos) * 0.25 + main.ball().pos
            self.add_subbehavior(skills.move.Move(self.intercept),
                                 'intercept direct',
                                 required=False,
                                 priority=5)

        for i in range(3):
            mark_i = skills.mark.Mark()
            mark_i.ratio = 0.7
            self.add_subbehavior(mark_i,
                                 'mark' + str(i),
                                 required=False,
                                 priority=3 - i)
            self.marks.append(mark_i)

        self.kick_eval = robocup.KickEvaluator(main.system_state())
        self.kick_eval.debug = True
        for i, robot in enumerate(main.our_robots()):
            self.kick_eval.add_excluded_robot(robot)

        for i, robot in enumerate(main.their_robots()):
            self.kick_eval.add_excluded_robot(robot)

        their_kicker = min(main.their_robots(),
                           key=lambda opp: opp.pos.dist_to(main.ball().pos))
        self.kick_eval.add_excluded_robot(their_kicker)
예제 #20
0
    def within_range(self):
        shortest_opp_dist = 10
        shortest_our_dist = 10
        # TODO: Do some sort of prediction as the ball moves
        target_pos = main.ball().pos

        # Find closest opponent robot
        for bot in main.their_robots():
            dist = self.estimate_path_length(bot.pos, target_pos,
                                             main.our_robots())
            if (dist < shortest_opp_dist):
                shortest_opp_dist = dist

        # Find closest robot on our team
        for bot in main.our_robots():
            dist = self.estimate_path_length(bot.pos, target_pos,
                                             main.their_robots())
            if (dist < shortest_our_dist):
                shortest_our_dist = dist

        # Greater than 1 when we are further away
        return shortest_our_dist < shortest_opp_dist * 1.05
예제 #21
0
def opponent_with_ball():
    closest_bot, closest_dist = None, float("inf")
    for bot in main.their_robots():
        if bot.visible:
            dist = (bot.pos - main.ball().pos).mag()
            if dist < closest_dist:
                closest_bot, closest_dist = bot, dist

    if closest_bot == None:
        return None
    else:
        if robot_has_ball(closest_bot):
            return closest_bot
        else:
            return None
예제 #22
0
def opponent_with_ball():
    closest_bot, closest_dist = None, float("inf")
    for bot in main.their_robots():
        if bot.visible:
            dist = (bot.pos - main.ball().pos).mag()
            if dist < closest_dist:
                closest_bot, closest_dist = bot, dist

    if closest_bot == None:
        return None
    else:
        if robot_has_ball(closest_bot):
            return closest_bot
        else:
            return None
예제 #23
0
    def execute_setup_penalty(self):
        pt = robocup.Point(0, robocup.Field_PenaltyDist)
        penalty_kicker = min(main.their_robots(),
                             key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(
            penalty_kicker.pos,
            penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = shot_line.intersection(Goalie.RobotSegment)
        if dest == None:
            self.robot.move_to(robocup.Point(0, constants.Robot.Radius))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.y = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
        self.robot.move_to(dest)
예제 #24
0
    def get_transition_point(self):
        segment = constants.Field.OurGoalSegment
        line = robocup.Line(main.ball().pos, main.their_robots()[0].pos)

        goalie_pos = constants.Field.OurGoalSegment.center()
        if (self.has_subbehavior_with_name('block')):
            block_robot = self.subbehavior_with_name('block').robot
            if (block_robot != None):
                goalie_pos = block_robot.pos

        #find the point that the robot is most likely going to shoot at
        goal_intercept = segment.line_intersection(line)

        #if robot is not lined up with the goal assume the bot will shoot center
        if goal_intercept == None:
            goal_intercept = segment.center()

        #get the vector of the ball to the ideal shot point
        ball_to_goal_intercept = goal_intercept - main.ball().pos

        #normalize the vector
        ball_to_goal_intercept = ball_to_goal_intercept.normalized()

        #the ideal spot to be will be the chip distance times the normalized vector from the ball's
        #current point.
        ideal_defence = ball_to_goal_intercept * self.chip_distance + main.ball(
        ).pos

        #find the line of the shot the robot will make
        ball_to_goal_segment = robocup.Segment(main.ball().pos, goal_intercept)

        #this is the point to get our robot to block the shot the quickest.
        fastest_defence = ball_to_goal_segment.nearest_point(goalie_pos)

        #if robot is blocking the shot already just go to the ideal point otherwise average the vectors
        #based on the blocking percentage.
        if (goalie_pos.dist_to(fastest_defence) <
            (constants.Robot.Radius / 4)):
            move_to_point = ideal_defence
        else:
            move_to_point = robocup.Point(
                (ideal_defence.x * (self.block_percentage)) +
                (fastest_defence.x * (1 - self.block_percentage)),
                ((ideal_defence.y * self.block_percentage) +
                 fastest_defence.y * (1 - self.block_percentage)))

        return move_to_point
예제 #25
0
def get_closest_opponent(pos, direction_weight=0, excluded_robots=[]):

    closest_bot, closest_dist = None, float("inf")
    for bot in main.their_robots():
        if bot.visible and bot not in excluded_robots:
            dist = (bot.pos - pos).mag()

            if (pos.y <= bot.pos.y):
                dist *= (2 - direction_weight / 2)
            else:
                dist *= (2 + direction_weight / 2)

            if dist < closest_dist:
                closest_bot = bot
                closest_dist = dist

    return closest_bot
예제 #26
0
def space_coeff_at_pos(pos, excluded_robots=[], robots=None):
    # TODO: Add in velocity prediction
    if robots == None:
        robots = main.their_robots()

    max_dist = robocup.Point(constants.Field.Width / 2,
                             constants.Field.Length).mag()
    total = 0
    sensitivity = 8

    for bot in robots:
        if bot.visible and bot not in excluded_robots:
            u = sensitivity * (bot.pos - pos).mag() / max_dist

            # Use Triweight kernal function (Force to be positive)
            # Graph looks much like a normal distribution
            total += max((35 / 32) * pow((1 - pow(u, 2)), 3), 0)

    return min(total, 1)
예제 #27
0
    def execute_setup_penalty(self):
        pt = robocup.Point(0, constants.Field.PenaltyDist)
        penalty_kicker = min(main.their_robots(),
                             key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(
            penalty_kicker.pos,
            penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = Goalie.RobotSegment.line_intersection(shot_line)
        if dest is None:
            self.robot.move_to(
                robocup.Point(0, constants.Robot.Radius + Goalie.OFFSET))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.x = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
            # Shots don't follow the top threat, they follow the inverse
            # FIXME this is kind of a hack
            dest.x = -dest.x
            self.robot.move_to(dest)
예제 #28
0
    def classify_opponent_robots(self):
        del self.wingers[:]
        del self.forwards[:]

        for bot in main.their_robots():
            if bot.visible and bot.pos.y < constants.Field.Length / 2:
                robot_risk_score = self.calculate_robot_risk_scores(bot)
                area_risk_score = self.calculate_area_risk_scores(bot)

                features = [robot_risk_score, area_risk_score]
                is_wing, class_score = evaluation.linear_classification.binary_classification(
                    features, WingerWall.WING_FORWARD_WEIGHTS,
                    WingerWall.WING_FORWARD_BIAS,
                    WingerWall.WING_FORWARD_CUTOFF)

                is_wing = not is_wing  #appears tobe inverted fix TODO

                if is_wing:
                    self.wingers.append((class_score, bot))
                else:
                    self.forwards.append((class_score, bot))
예제 #29
0
    def opp_robot_blocking(self):
        if (self.robot is None):
            return False

        # Closest opp robot in any direction
        # To us, not the ball   
        closest_opp_robot = None
        closest_opp_dist = float("inf")
        for r in main.their_robots():
            if ((r.pos - self.robot.pos).mag() < closest_opp_dist):
                closest_opp_robot = r
                closest_opp_dist = (r.pos - self.robot.pos).mag()

        # Only do this if a robot is in range
        robot_in_range = closest_opp_dist < .2 + 2 * constants.Robot.Radius

        aim_dir = robocup.Point.direction(self.robot.angle)
        robot_dir = (closest_opp_robot.pos - self.robot.pos)

        # Only trigger if they are infront of us
        robot_in_front = aim_dir.dot(robot_dir) > 0

        closest_pt = robocup.Line(
            self.robot.pos,
            self.robot.pos + aim_dir).nearest_point(closest_opp_robot.pos)

        does_hit_robot = (closest_opp_robot.pos - closest_pt
                          ).mag() < constants.Robot.Radius

        facing_their_side = robocup.Point.direction(self.robot.angle).y > 0

        ret = (facing_their_side and robot_in_range and robot_in_front and
               does_hit_robot)

        if ret:
            print("Panic kick")
            main.debug_drawer().draw_text('panic kick', self.robot.pos,
                                          (255, 255, 255), 'PivotKick')

        return ret
예제 #30
0
    def execute_setup_penalty(self):
        if main.ball().valid:
            pt = main.ball().pos
        else:
            # FIXME is this correct?
            pt = robocup.Point(0, constants.Field.PenaltyLongDist)
        penalty_kicker = min(main.their_robots(),
                             key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(
            penalty_kicker.pos,
            penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = Goalie.RobotSegment.line_intersection(shot_line)
        if dest is None:
            self.robot.move_to(
                robocup.Point(0, constants.Robot.Radius + Goalie.OFFSET))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.x = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
            # Shots don't follow the top threat, they follow the inverse
            # FIXME this is kind of a hack
            dest.x = -dest.x
            self.robot.move_to(dest)
예제 #31
0
    def eval_pt_to_seg(self, origin, target):
        end = target.delta().magsq()

        # if target is a zero-length segment, there are no windows
        if end == 0:
            return [], None

        if self.debug:
            main.system_state().draw_line(target, constants.Colors.Blue, "Debug")

        windows = [Window(0, end)]

        # apply the obstacles
        bots = filter(lambda bot: bot not in self.excluded_robots and bot.visible, (list(main.our_robots()) + list(main.their_robots())))
        bot_locations = list(map(lambda bot: bot.pos, bots))
        bot_locations.extend(self.hypothetical_robot_locations)
        for pos in bot_locations:
            d = (pos - origin).mag()
            # whether or not we can chip over this bot
            chip_overable = (self.chip_enabled
                            and (d < self.max_chip_range - constants.Robot.Radius)
                            and (d > self.min_chip_range + constants.Robot.Radius))
            if not chip_overable:
                self.obstacle_robot(windows, origin, target, pos)

        # set the segment and angles for each window
        p0 = target.get_pt(0)
        delta = target.delta() / end

        for w in windows:
            w.segment = robocup.Segment(p0 + delta * w.t0, p0 + delta * w.t1)
            w.a0 = (w.segment.get_pt(0) - origin).angle() * constants.RadiansToDegrees
            w.a1 = (w.segment.get_pt(1) - origin).angle() * constants.RadiansToDegrees

        best = max(windows, key=lambda w: w.segment.delta().magsq()) if len(windows) > 0 else None

        if self.debug and best is not None:
            main.system_state().draw_line(best.segment, constants.Colors.Green, "Debug")
            main.system_state().draw_line(robocup.Line(origin, best.segment.center()), constants.Colors.Green, "Debug")

        # # draw the windows if we're in debug mode
        # if self.debug:
        #     for w in windows:
        #         pts = [origin, w.segment.get_pt(0), w.segment.get_pt(1)]
        #         color = (255, 0, 0) if w == best else (0, 255, 0)
        #         main.system_state().draw_polygon(pts, 3, color, "Windows")

        return windows, best
예제 #32
0
    def recalculate(self):
        goalie = self.subbehavior_with_name('goalie')
        defender1 = self.subbehavior_with_name('defender1')
        defender2 = self.subbehavior_with_name('defender2')
        behaviors = [goalie, defender1, defender2]

        # if we don't have any bots to work with, don't waste time calculating
        if all(bhvr.robot == None for bhvr in behaviors):
            return


        # A threat to our goal - something we'll actively defend against
        class Threat:
            def __init__(self, source=None):
                self.source = source
                self.ball_acquire_chance = 1.0
                self.shot_chance = 1.0
                self.assigned_handlers = []
                self.best_shot_window = None


            # an OpponentRobot or Point
            @property
            def source(self):
                return self._source
            @source.setter
            def source(self, value):
                self._source = value


            # our source can be a Point or an OpponentRobot, this method returns the location of it
            @property
            def pos(self):
                if self.source != None:
                    return self.source if isinstance(self.source, robocup.Point) else self.source.pos
            

            # a list of our behaviors that will be defending against this threat
            # as of now only Defender and Goalie
            @property
            def assigned_handlers(self):
                return self._assigned_handlers
            @assigned_handlers.setter
            def assigned_handlers(self, value):
                self._assigned_handlers = value


            # our estimate of the chance that this threat will acquire the ball
            # 1.0 if it already has it
            # otherwise, a value from 0 to 1 gauging its likelihood to receive a pass
            @property
            def ball_acquire_chance(self):
                return self._ball_acquire_chance
            @ball_acquire_chance.setter
            def ball_acquire_chance(self, value):
                self._ball_acquire_chance = value
            

            # our estimate of the chance of this threat making its shot on the goal given that it gets/has the ball
            # NOTE: this is calculated excluding all of our robots on the field as obstacles
            @property
            def shot_chance(self):
                return self._shot_chance
            @shot_chance.setter
            def shot_chance(self, value):
                self._shot_chance = value
            

            # his best window on our goal
            @property
            def best_shot_window(self):
                return self._best_shot_window
            @best_shot_window.setter
            def best_shot_window(self, value):
                self._best_shot_window = value
            


            # our assessment of the risk of this threat
            # should be between 0 and 1
            @property
            def score(self):
                return self.ball_acquire_chance * self.shot_chance
            
        

        # available behaviors we have to assign to threats
        # only look at ones that have robots
        # as we handle threats, we remove the handlers from this list
        unused_threat_handlers = list(filter(lambda bhvr: bhvr.robot != None, [goalie, defender1, defender2]))



        def set_block_lines_for_threat_handlers(threat):
            if len(threat.assigned_handlers) == 0:
                return

            # make sure goalie is in the middle
            if len(threat.assigned_handlers) > 1:
                if goalie in threat.assigned_handlers:
                    idx = threat.assigned_handlers.index(goalie)
                    if idx != 1:
                        del threat.assigned_handlers[idx]
                        threat.assigned_handlers.insert(1, goalie)


            if threat.best_shot_window != None:
                center_line = robocup.Line(threat.pos, threat.best_shot_window.segment.center())
            else:
                center_line = robocup.Line(threat.pos, constants.Field.OurGoalSegment.center())


            # find the angular width that each defender can block.  We then space these out accordingly
            angle_widths = []
            for handler in threat.assigned_handlers:
                dist_from_threat = handler.robot.pos.dist_to(threat.pos)
                w = min(2.0 * math.atan2(constants.Robot.Radius, dist_from_threat), 0.15)
                angle_widths.append(w)


            # start on one edge of our available angle coverage and work counter-clockwise,
            # assigning block lines to the bots as we go
            spacing = 0.01 if len(threat.assigned_handlers) < 3 else 0.0  # spacing between each bot in radians
            total_angle_coverage = sum(angle_widths) + (len(angle_widths) - 1)*spacing
            start_vec = center_line.delta().normalized()
            start_vec.rotate(robocup.Point(0,0), -total_angle_coverage / 2.0)
            for i in range(len(angle_widths)):
                handler = threat.assigned_handlers[i]
                w = angle_widths[i]
                start_vec.rotate(robocup.Point(0,0), w/2.0)
                handler.block_line = robocup.Line(threat.pos, threat.pos + start_vec * 10)
                start_vec.rotate(robocup.Point(0,0), w/2.0 + spacing)



        def recalculate_threat_shot(threat_index):
            if not isinstance(threat_index, int):
                raise TypeError("threat_index should be an int")

            # ignore all of our robots
            excluded_robots = list(main.our_robots())

            # behaviors before this threat are counted as obstacles in their TARGET position (where we've
            # assigned them to go, not where they are right now)
            hypothetical_obstacles = []
            for t in threats[0:threat_index]:
                hypothetical_obstacles.extend(map(lambda bhvr: bhvr.move_target, t.assigned_handlers))

            threat = threats[threat_index]
            threat.shot_chance, threat.best_shot_window = evaluation.shot.eval_shot(
                pos=threat.pos,
                target=constants.Field.OurGoalSegment,
                windowing_excludes=excluded_robots,
                hypothetical_robot_locations=[],
                debug=False)


        threats = []


        # secondary threats are those that are somewhat close to our goal and open for a pass
        # if they're farther than this down the field, we don't consider them threats
        threat_max_y = constants.Field.Length / 2.0
        potential_threats = [opp for opp in main.their_robots() if opp.pos.y < threat_max_y]


        # find the primary threat
        # if the ball is not moving OR it's moving towards our goal, it's the primary threat
        # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it
        if main.ball().vel.mag() > 0.4:
            # the line the ball's moving along
            ball_travel_line = robocup.Line(main.ball().pos, main.ball().pos + main.ball().vel)

            # this is a shot on the goal!
            if evaluation.ball.is_moving_towards_our_goal():
                ball_threat = Threat(main.ball().pos)
                ball_threat.ball_acquire_chance = 1.0
                ball_threat.shot_chance = 1.0
                threats.append(ball_threat)
            else:
                # Check for a bot that's about to capture this ball and potentially shoot on the goal
                # potential_receivers is an array of (OpponentRobot, angle) tuples, where the angle
                # is the angle between the ball_travel_line and the line from the ball to the opponent
                # bot - this is our metric for receiver likeliness.
                potential_receivers = []
                for opp in potential_threats:
                    # see if the bot is in the direction the ball is moving
                    if (opp.pos - ball_travel_line.get_pt(0)).dot(ball_travel_line.delta()) > 0:
                        # calculate the angle and add it to the list if it's within reason
                        nearest_pt = ball_travel_line.nearest_point(opp.pos)
                        dx = (nearest_pt - main.ball().pos).mag()
                        dy = (opp.pos - nearest_pt).mag()
                        angle = abs(math.atan2(dy, dx))
                        if angle < math.pi / 4.0:
                            potential_receivers.append( (opp, 1.0) )

                # choose the receiver with the smallest angle from the ball travel line
                if len(potential_receivers) > 0:
                    best_receiver_tuple = min(potential_receivers, key=lambda rcrv_tuple: rcrv_tuple[1])
                    if best_receiver_tuple != None:
                        receiver_threat = Threat(best_receiver_tuple[0])
                        receiver_threat.ball_acquire_chance = 0.9   # note: this value is arbitrary
                        receiver_threat.shot_chance = 0.9   # FIXME: calculate this
                        threats.append(receiver_threat)
                else:
                    ball_threat = Threat(main.ball().pos)
                    ball_threat.ball_acquire_chance = 1.0
                    ball_threat.shot_chance = 0.9
                    threats.append(ball_threat)

        else:
            # primary threat is the ball or the opponent holding it
            opp_with_ball = evaluation.ball.opponent_with_ball()

            threat = Threat(opp_with_ball if opp_with_ball != None else main.ball().pos)
            threat.ball_acquire_chance = 1.0
            threat.shot_chance = 1.0    # FIXME: calculate, don't use 1.0
            threats.append(threat)

 

        # if an opponent has the ball or is potentially about to receive the ball,
        # we look at potential receivers of it as threats
        if isinstance(threats[0].source, robocup.OpponentRobot):
            for opp in filter(lambda t: t.visible, potential_threats):
                pass_chance = evaluation.passing.eval_pass(main.ball().pos, opp.pos, excluded_robots=[opp])
                # give it a small chance because the obstacles in the way could move soon and we don't want to consider it a zero threatos, )
                if pass_chance < 0.001: pass_chance = 0.4 


                # record the threat
                threat = Threat(opp)
                threat.ball_acquire_chance = pass_chance
                threats.append(threat)

                # Now we evaluate this opponent's shot on the goal
                # exclude robots that have already been assigned to handle other threats
                threat.shot_chance, threat.best_shot_window = evaluation.shot.eval_shot(
                    pos=opp.pos,
                    target=constants.Field.OurGoalSegment,
                    windowing_excludes=map(lambda bhvr: bhvr.robot, unused_threat_handlers),
                    debug=False)

                if threat.shot_chance == 0:
                    # gve it a small chance because the shot could clear up a bit later and we don't want to consider it a zero threat
                    threat.shot_chance = 0.2


        else:
            # the ball isn't possessed by an opponent, so we just look at opponents with shots on the goal
            for opp in potential_threats:
                # record the threat
                lurker = Threat(opp)
                lurker.ball_acquire_chance = 0.5 # note: this is a bullshit value
                threats.append(lurker)
                recalculate_threat_shot(len(threats) - 1)


        # only consider the top three threats
        threats.sort(key=lambda threat: threat.score, reverse=True)
        threats = threats[0:3]

        # print("sorted threats:")
        # for idx, t in enumerate(threats):
        #     print("t[" + str(idx) + "]: " + str(t.source) + "shot: " + str(t.shot_chance) + "; pass:"******"; score:" + str(t.score))


        # print("sorted threat scores: " + str(list(map(lambda t: str(t.score) + " " + str(t.source), threats))))


        # print("Unused handlers: " + str(unused_threat_handlers))
        # print("---------------------")




        smart = False
        if not smart:

            # only deal with top two threats
            threats_to_block = threats[0:2]

            # print('threats to block: ' + str(list(map(lambda t: t.source, threats_to_block))))
            threat_idx = 0
            while len(unused_threat_handlers) > 0:
                threats_to_block[threat_idx].assigned_handlers.append(unused_threat_handlers[0])
                del unused_threat_handlers[0]

                threat_idx = (threat_idx + 1) % len(threats_to_block)
                

            for t_idx, t in enumerate(threats_to_block):
                recalculate_threat_shot(t_idx)
                set_block_lines_for_threat_handlers(t)


        else:
            # assign all of our defenders to do something
            while len(unused_threat_handlers) > 0:
                # prioritize by threat score, highest first
                top_threat = max(threats, key=lambda threat: threat.score)

                # assign the next handler to this threat
                handler = unused_threat_handlers[0]
                top_threat.assigned_handlers.append(handler)
                del unused_threat_handlers[0]

                # reassign the block line for each handler of this threat
                set_block_lines_for_threat_handlers(top_threat)

                # recalculate the shot now that we have
                recalculate_threat_shot(0)


        # tell the bots where to move / what to block and draw some debug stuff
        for idx, threat in enumerate(threats):

            # recalculate, including all current bots
            # FIXME: do we want this?
            # recalculate_threat_shot(idx)

            # the line they'll be shooting down/on
            if threat.best_shot_window != None:
                shot_line = robocup.Segment(threat.pos, threat.best_shot_window.segment.center())
            else:
                shot_line = robocup.Segment(threat.pos, robocup.Point(0, 0))


            # debug output
            if self.debug:
                for handler in threat.assigned_handlers:
                    # handler.robot.add_text("Marking: " + str(threat.source), constants.Colors.White, "Defense")
                    main.system_state().draw_circle(handler.move_target, 0.02, constants.Colors.Blue, "Defense")


                # draw some debug stuff
                if threat.best_shot_window != None:
                    # draw shot triangle
                    pts = [threat.pos, threat.best_shot_window.segment.get_pt(0), threat.best_shot_window.segment.get_pt(1)]
                    shot_color = (255, 0, 0, 150)   # translucent red
                    main.system_state().draw_polygon(pts, shot_color, "Defense")
                    main.system_state().draw_line(threat.best_shot_window.segment, constants.Colors.Red, "Defense")

                    chance, best_window = evaluation.shot.eval_shot(threat.pos, constants.Field.OurGoalSegment)

                    main.system_state().draw_text("Shot: " + str(int(threat.shot_chance * 100.0)) + "% / " + str(int(chance*100)) + "%", shot_line.center(), constants.Colors.White, "Defense")
                
                # draw pass lines
                if idx > 0:
                    pass_line = robocup.Segment(main.ball().pos, threat.pos)
                    main.system_state().draw_line(pass_line, constants.Colors.Red, "Defense")
                    main.system_state().draw_text("Pass: "******"%", pass_line.center(), constants.Colors.White, "Defense")
예제 #33
0
    def get_threat_list(self, unused_threat_handlers):
        # List of (position, score, Robot/None)
        threats = []
        potential_threats = main.their_robots()

        # find the primary threat
        # if the ball is not moving OR it's moving towards our goal, it's the primary threat
        # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it
        if (main.ball().vel.mag() > 0.4):
            if evaluation.ball.is_moving_towards_our_goal():
                # Add tuple of pos and score
                threats.append((main.ball().pos, 1, None))
            else:
                # Get all potential receivers
                potential_receivers = []
                for opp in potential_threats:
                    if self.estimate_potential_recievers_score(opp) == 1:
                        potential_receivers.append((opp.pos, 1, opp))

                if len(potential_receivers) > 0:
                    # Add best receiver to threats
                    # TODO Calc shot chance
                    best_tuple = min(potential_receivers,
                                     key=lambda rcrv_tuple: rcrv_tuple[1])
                    threats.append((best_tuple[0], .81, best_tuple[2]))
                else:
                    # Just deal with ball if no recievers
                    threats.append((main.ball().pos, .9, None))
        else:
            # Assume opp is dribbling ball
            if not constants.Field.OurGoalZoneShape.contains_point(
                    main.ball().pos):
                # TODO: Calc shot chance
                threats.append((main.ball().pos, 1, None))

        # if there are threats, check pass and shot chances
        # If the first item is not a ball, it is most likely a pass
        if len(threats) > 0 and threats[0][0] != main.ball().pos:
            for opp in potential_threats:

                # Exclude robots that have been assigned already
                excluded_bots = []
                for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers):
                    excluded_bots.append(r)

                threats.append((opp.pos, self.estimate_risk_score(
                    opp, excluded_bots), opp))
        else:
            for opp in potential_threats:

                # Exclude all robots
                self.kick_eval.excluded_robots.clear()
                self.kick_eval.add_excluded_robot(opp)
                for r in main.our_robots():
                    self.kick_eval.add_excluded_robot(r)

                point, shotChance = self.kick_eval.eval_pt_to_our_goal(opp.pos)

                # Note: 0.5 is a bullshit value
                threats.append((opp.pos, 0.5 * shotChance, opp))

        # Prevent threats from being below our goal line (causes incorrect pos)
        def _adjust_pt(threat):
            pt = threat[0]
            pt.y = max(pt.y, 0.1)
            return (pt,) + threat[1:]

        threats = list(map(_adjust_pt, threats))

        return threats
예제 #34
0
 def on_enter_running(self):
 	b = skills.mark.Mark()
 	b.mark_robot = main.their_robots()[0]
 	self.add_subbehavior(b, name='mark', required=True)
예제 #35
0
    def recalculate(self):
        goalie = self.subbehavior_with_name('goalie')
        defender1 = self.subbehavior_with_name('defender1')
        defender2 = self.subbehavior_with_name('defender2')
        behaviors = [goalie, defender1, defender2]

        # if we don't have any bots to work with, don't waste time calculating
        if all(bhvr.robot == None for bhvr in behaviors):
            return

        # A threat to our goal - something we'll actively defend against
        class Threat:
            def __init__(self, source=None):
                self.source = source
                self.ball_acquire_chance = 1.0
                self.shot_chance = 1.0
                self.assigned_handlers = []
                self.best_shot_window = None

            # an OpponentRobot or Point
            @property
            def source(self):
                return self._source

            @source.setter
            def source(self, value):
                self._source = value

            # our source can be a Point or an OpponentRobot, this method returns the location of it
            @property
            def pos(self):
                if self.source != None:
                    return self.source if isinstance(
                        self.source, robocup.Point) else self.source.pos

            # a list of our behaviors that will be defending against this threat
            # as of now only Defender and Goalie
            @property
            def assigned_handlers(self):
                return self._assigned_handlers

            @assigned_handlers.setter
            def assigned_handlers(self, value):
                self._assigned_handlers = value

            # our estimate of the chance that this threat will acquire the ball
            # 1.0 if it already has it
            # otherwise, a value from 0 to 1 gauging its likelihood to receive a pass
            @property
            def ball_acquire_chance(self):
                return self._ball_acquire_chance

            @ball_acquire_chance.setter
            def ball_acquire_chance(self, value):
                self._ball_acquire_chance = value

            # our estimate of the chance of this threat making its shot on the goal given that it gets/has the ball
            # NOTE: this is calculated excluding all of our robots on the field as obstacles
            @property
            def shot_chance(self):
                return self._shot_chance

            @shot_chance.setter
            def shot_chance(self, value):
                self._shot_chance = value

            # his best window on our goal
            @property
            def best_shot_window(self):
                return self._best_shot_window

            @best_shot_window.setter
            def best_shot_window(self, value):
                self._best_shot_window = value

            # our assessment of the risk of this threat
            # should be between 0 and 1
            @property
            def score(self):
                return self.ball_acquire_chance * self.shot_chance

            # available behaviors we have to assign to threats
            # only look at ones that have robots
            # as we handle threats, we remove the handlers from this list

        unused_threat_handlers = list(
            filter(lambda bhvr: bhvr.robot != None,
                   [goalie, defender1, defender2]))

        def set_block_lines_for_threat_handlers(threat):
            if len(threat.assigned_handlers) == 0:
                return

            # make sure goalie is in the middle
            if len(threat.assigned_handlers) > 1:
                if goalie in threat.assigned_handlers:
                    idx = threat.assigned_handlers.index(goalie)
                    if idx != 1:
                        del threat.assigned_handlers[idx]
                        threat.assigned_handlers.insert(1, goalie)

            if threat.best_shot_window != None:
                center_line = robocup.Line(
                    threat.pos, threat.best_shot_window.segment.center())
            else:
                center_line = robocup.Line(
                    threat.pos, constants.Field.OurGoalSegment.center())

            # find the angular width that each defender can block.  We then space these out accordingly
            angle_widths = []
            for handler in threat.assigned_handlers:
                dist_from_threat = handler.robot.pos.dist_to(threat.pos)
                w = min(
                    2.0 * math.atan2(constants.Robot.Radius, dist_from_threat),
                    0.15)
                angle_widths.append(w)

            # start on one edge of our available angle coverage and work counter-clockwise,
            # assigning block lines to the bots as we go
            spacing = 0.01 if len(
                threat.assigned_handlers
            ) < 3 else 0.0  # spacing between each bot in radians
            total_angle_coverage = sum(angle_widths) + (len(angle_widths) -
                                                        1) * spacing
            start_vec = center_line.delta().normalized()
            start_vec.rotate(robocup.Point(0, 0), -total_angle_coverage / 2.0)
            for i in range(len(angle_widths)):
                handler = threat.assigned_handlers[i]
                w = angle_widths[i]
                start_vec.rotate(robocup.Point(0, 0), w / 2.0)
                handler.block_line = robocup.Line(threat.pos,
                                                  threat.pos + start_vec * 10)
                start_vec.rotate(robocup.Point(0, 0), w / 2.0 + spacing)

        def recalculate_threat_shot(threat_index):
            if not isinstance(threat_index, int):
                raise TypeError("threat_index should be an int")

            # ignore all of our robots
            excluded_robots = list(main.our_robots())

            # behaviors before this threat are counted as obstacles in their TARGET position (where we've
            # assigned them to go, not where they are right now)
            hypothetical_obstacles = []
            for t in threats[0:threat_index]:
                hypothetical_obstacles.extend(
                    map(lambda bhvr: bhvr.move_target, t.assigned_handlers))

            threat = threats[threat_index]
            self.win_eval.excluded_robots.clear()
            for r in excluded_robots:
                self.win_eval.add_excluded_robot(r)
            _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal(
                threat.pos)
            if threat.best_shot_window is not None:
                threat.shot_chance = threat.best_shot_window.shot_success
            else:
                threat.shot_chance = 0.0

        threats = []

        # secondary threats are those that are somewhat close to our goal and open for a pass
        # if they're farther than this down the field, we don't consider them threats
        threat_max_y = constants.Field.Length / 2.0
        potential_threats = [
            opp for opp in main.their_robots() if opp.pos.y < threat_max_y
        ]

        # find the primary threat
        # if the ball is not moving OR it's moving towards our goal, it's the primary threat
        # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it
        if main.ball().vel.mag() > 0.4:
            # the line the ball's moving along
            ball_travel_line = robocup.Line(main.ball().pos,
                                            main.ball().pos + main.ball().vel)

            # this is a shot on the goal!
            if evaluation.ball.is_moving_towards_our_goal():
                ball_threat = Threat(main.ball().pos)
                ball_threat.ball_acquire_chance = 1.0
                ball_threat.shot_chance = 1.0
                threats.append(ball_threat)
            else:
                # Check for a bot that's about to capture this ball and potentially shoot on the goal
                # potential_receivers is an array of (OpponentRobot, angle) tuples, where the angle
                # is the angle between the ball_travel_line and the line from the ball to the opponent
                # bot - this is our metric for receiver likeliness.
                potential_receivers = []
                for opp in potential_threats:
                    # see if the bot is in the direction the ball is moving
                    if (opp.pos - ball_travel_line.get_pt(0)).dot(
                            ball_travel_line.delta()) > 0:
                        # calculate the angle and add it to the list if it's within reason
                        nearest_pt = ball_travel_line.nearest_point(opp.pos)
                        dx = (nearest_pt - main.ball().pos).mag()
                        dy = (opp.pos - nearest_pt).mag()
                        angle = abs(math.atan2(dy, dx))
                        if angle < math.pi / 4.0:
                            potential_receivers.append((opp, 1.0))

                # choose the receiver with the smallest angle from the ball travel line
                if len(potential_receivers) > 0:
                    best_receiver_tuple = min(
                        potential_receivers,
                        key=lambda rcrv_tuple: rcrv_tuple[1])
                    if best_receiver_tuple != None:
                        receiver_threat = Threat(best_receiver_tuple[0])
                        receiver_threat.ball_acquire_chance = 0.9  # note: this value is arbitrary
                        receiver_threat.shot_chance = 0.9  # FIXME: calculate this
                        threats.append(receiver_threat)
                else:
                    ball_threat = Threat(main.ball().pos)
                    ball_threat.ball_acquire_chance = 1.0
                    ball_threat.shot_chance = 0.9
                    threats.append(ball_threat)

        else:
            # primary threat is the ball or the opponent holding it
            opp_with_ball = evaluation.ball.opponent_with_ball()

            threat = Threat(
                opp_with_ball if opp_with_ball != None else main.ball().pos)
            threat.ball_acquire_chance = 1.0
            threat.shot_chance = 1.0  # FIXME: calculate, don't use 1.0
            threats.append(threat)

# if an opponent has the ball or is potentially about to receive the ball,
# we look at potential receivers of it as threats
        if isinstance(threats[0].source, robocup.OpponentRobot):
            for opp in filter(lambda t: t.visible, potential_threats):
                pass_chance = evaluation.passing.eval_pass(
                    main.ball().pos, opp.pos, excluded_robots=[opp])
                # give it a small chance because the obstacles in the way could move soon and we don't want to consider it a zero threatos, )
                if pass_chance < 0.001: pass_chance = 0.4

                # record the threat
                threat = Threat(opp)
                threat.ball_acquire_chance = pass_chance
                threats.append(threat)

                # Now we evaluate this opponent's shot on the goal
                # exclude robots that have already been assigned to handle other threats
                self.win_eval.excluded_robots.clear()
                for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers):
                    self.win_eval.add_excluded_robot(r)
                _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal(
                    opp.pos)
                if threat.best_shot_window is not None:
                    threat.shot_chance = threat.best_shot_window.shot_success
                else:
                    threat.shot_chance = 0.0

                if threat.shot_chance == 0:
                    # gve it a small chance because the shot could clear up a bit later and we don't want to consider it a zero threat
                    threat.shot_chance = 0.2

        else:
            # the ball isn't possessed by an opponent, so we just look at opponents with shots on the goal
            for opp in potential_threats:
                # record the threat
                lurker = Threat(opp)
                lurker.ball_acquire_chance = 0.5  # note: this is a bullshit value
                threats.append(lurker)
                recalculate_threat_shot(len(threats) - 1)

        # only consider the top three threats
        threats.sort(key=lambda threat: threat.score, reverse=True)
        threats = threats[0:3]

        # print("sorted threats:")
        # for idx, t in enumerate(threats):
        #     print("t[" + str(idx) + "]: " + str(t.source) + "shot: " + str(t.shot_chance) + "; pass:"******"; score:" + str(t.score))

        # print("sorted threat scores: " + str(list(map(lambda t: str(t.score) + " " + str(t.source), threats))))

        # print("Unused handlers: " + str(unused_threat_handlers))
        # print("---------------------")

        smart = False
        if not smart:

            # only deal with top two threats
            threats_to_block = threats[0:2]

            # print('threats to block: ' + str(list(map(lambda t: t.source, threats_to_block))))
            threat_idx = 0
            while len(unused_threat_handlers) > 0:
                threats_to_block[threat_idx].assigned_handlers.append(
                    unused_threat_handlers[0])
                del unused_threat_handlers[0]

                threat_idx = (threat_idx + 1) % len(threats_to_block)

            for t_idx, t in enumerate(threats_to_block):
                recalculate_threat_shot(t_idx)
                set_block_lines_for_threat_handlers(t)

        else:
            # assign all of our defenders to do something
            while len(unused_threat_handlers) > 0:
                # prioritize by threat score, highest first
                top_threat = max(threats, key=lambda threat: threat.score)

                # assign the next handler to this threat
                handler = unused_threat_handlers[0]
                top_threat.assigned_handlers.append(handler)
                del unused_threat_handlers[0]

                # reassign the block line for each handler of this threat
                set_block_lines_for_threat_handlers(top_threat)

                # recalculate the shot now that we have
                recalculate_threat_shot(0)

        # tell the bots where to move / what to block and draw some debug stuff
        for idx, threat in enumerate(threats):

            # recalculate, including all current bots
            # FIXME: do we want this?
            # recalculate_threat_shot(idx)

            # the line they'll be shooting down/on
            if threat.best_shot_window != None:
                shot_line = robocup.Segment(
                    threat.pos, threat.best_shot_window.segment.center())
            else:
                shot_line = robocup.Segment(threat.pos, robocup.Point(0, 0))

            # debug output
            if self.debug:
                for handler in threat.assigned_handlers:
                    # handler.robot.add_text("Marking: " + str(threat.source), constants.Colors.White, "Defense")
                    main.system_state().draw_circle(handler.move_target, 0.02,
                                                    constants.Colors.Blue,
                                                    "Defense")

                # draw some debug stuff
                if threat.best_shot_window != None:
                    # draw shot triangle
                    pts = [
                        threat.pos,
                        threat.best_shot_window.segment.get_pt(0),
                        threat.best_shot_window.segment.get_pt(1)
                    ]
                    shot_color = (255, 0, 0, 150)  # translucent red
                    main.system_state().draw_polygon(pts, shot_color,
                                                     "Defense")
                    main.system_state().draw_segment(
                        threat.best_shot_window.segment, constants.Colors.Red,
                        "Defense")

                    self.win_eval.excluded_robots.clear()
                    _, best_window = self.win_eval.eval_pt_to_our_goal(
                        threat.pos)
                    if best_window is not None:
                        chance = best_window.shot_success
                    else:
                        chance = 0.0

                    main.system_state().draw_text(
                        "Shot: " + str(int(threat.shot_chance * 100.0)) +
                        "% / " + str(int(chance * 100)) + "%",
                        shot_line.center(), constants.Colors.White, "Defense")

                # draw pass lines
                if idx > 0:
                    pass_line = robocup.Segment(main.ball().pos, threat.pos)
                    main.system_state().draw_line(pass_line,
                                                  constants.Colors.Red,
                                                  "Defense")
                    main.system_state().draw_text(
                        "Pass: "******"%",
                        pass_line.center(), constants.Colors.White, "Defense")
예제 #36
0
    def execute_running(self):
        their_robots = main.their_robots()
        mark_one = self.subbehavior_with_name('mark_one')
        mark_two = self.subbehavior_with_name('mark_two')

        centerCircle = robocup.Circle(constants.Field.CenterPoint,
                                      constants.Field.CenterRadius)

        # Don't select robots that are
        # 1. Not on our side of the field
        # 2. behind or inside the goal circle
        mark_robot_right = list(filter(
            lambda robot: (robot.pos.x >= 0 and robot.pos.y < constants.Field.Length * TheirKickoff.FieldRatio and constants.Field.FieldRect.contains_point(robot.pos) and not centerCircle.contains_point(robot.pos)),
            their_robots))

        # Don't select robots that are
        # 1. Not on our side of the field
        # 2. behind or inside the goal circle
        # 3. Not the robot selected before
        mark_robot_left = list(filter(
            lambda robot: (robot.pos.x <= 0 and robot.pos.y < constants.Field.Length * TheirKickoff.FieldRatio and constants.Field.FieldRect.contains_point(robot.pos) and not centerCircle.contains_point(robot.pos) and robot != mark_one.mark_robot),
            their_robots))

        # Special cases
        if len(mark_robot_left) + len(mark_robot_right) == 0:
            # Can't do anything
            mark_robot_left = None
            mark_robot_right = None
        elif len(mark_robot_left) + len(mark_robot_right) == 1:
            if len(mark_robot_left) == 1:
                mark_robot_right = mark_robot_left[0]
                mark_robot_left = None
            else:
                mark_robot_right = mark_robot_right[0]
                mark_robot_left = None
        elif len(mark_robot_left) == 0:
            mark_robot_right = mark_robot_right
            mark_robot_left = mark_robot_right
        elif len(mark_robot_right) == 0:
            mark_robot_right = mark_robot_left
            mark_robot_left = mark_robot_left
        # Else, everything can proceed as normal (pick best one from each side)

        # Make every element a list to normalize for the next step
        if type(mark_robot_right) is not list and mark_robot_right is not None:
            mark_robot_right = [mark_robot_right]
        if type(mark_robot_left) is not list and mark_robot_left is not None:
            mark_robot_left = [mark_robot_left]

        # Select best robot from candidate lists
        selected = None
        if mark_robot_right is not None:
            mark_robot_right = min(mark_robot_right,
                                   key=lambda robot: robot.pos.y).pos
            selected = robocup.Point(mark_robot_right)
        else:
            mark_robot_right = robocup.Point(TheirKickoff.DefaultDist,
                                             constants.Field.Length / 2)
        # Set x and y seperately as we want a constant y value (just behind the kick off line)
        mark_robot_right.y = min(
            constants.Field.Length / 2 - TheirKickoff.LineBuffer,
            mark_robot_right.y)
        mark_robot_right.x = self.absmin(mark_robot_right.x,
                                         TheirKickoff.DefaultDist)
        mark_one.mark_point = mark_robot_right

        # Do the same thing as above on the left robot.
        if mark_robot_left is not None:
            # Don't mark the same robot twice
            mark_robot_left = filter(
                lambda x: True if selected is None else not x.pos.nearly_equals(selected),
                mark_robot_left)
            mark_robot_left = min(mark_robot_left,
                                  key=lambda robot: robot.pos.y).pos
        else:
            mark_robot_left = robocup.Point(-TheirKickoff.DefaultDist,
                                            constants.Field.Length / 2)
        mark_robot_left.y = min(
            constants.Field.Length / 2 - TheirKickoff.LineBuffer,
            mark_robot_left.y)
        mark_robot_left.x = self.absmin(mark_robot_left.x,
                                        TheirKickoff.DefaultDist)
        mark_two.mark_point = mark_robot_left
예제 #37
0
    def get_threat_list(self, unused_threat_handlers):
        # List of (position, score, Robot/None)
        threats = []
        potential_threats = main.their_robots()

        # find the primary threat
        # if the ball is not moving OR it's moving towards our goal, it's the primary threat
        # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it
        if (main.ball().vel.mag() > 0.4):
            if evaluation.ball.is_moving_towards_our_goal():
                # Add tuple of pos and score
                threats.append((main.ball().pos, 1, None))
            else:
                # Get all potential receivers
                potential_receivers = []
                for opp in potential_threats:
                    if self.estimate_potential_recievers_score(opp) == 1:
                        potential_receivers.append((opp.pos, 1, opp))

                if len(potential_receivers) > 0:
                    # Add best receiver to threats
                    # TODO Calc shot chance
                    best_tuple = min(potential_receivers,
                                     key=lambda rcrv_tuple: rcrv_tuple[1])
                    threats.append((best_tuple[0], .81, best_tuple[2]))
                else:
                    # Just deal with ball if no recievers
                    threats.append((main.ball().pos, .9, None))
        else:
            # Assume opp is dribbling ball
            if not constants.Field.OurGoalZoneShape.contains_point(
                    main.ball().pos):
                # TODO: Calc shot chance
                threats.append((main.ball().pos, 1, None))

        # if there are threats, check pass and shot chances
        # If the first item is not a ball, it is most likely a pass
        if len(threats) > 0 and threats[0][0] != main.ball().pos:
            for opp in potential_threats:

                # Exclude robots that have been assigned already
                excluded_bots = []
                for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers):
                    excluded_bots.append(r)

                threats.append(
                    (opp.pos, self.estimate_risk_score(opp,
                                                       excluded_bots), opp))
        else:
            for opp in potential_threats:

                # Exclude all robots
                self.kick_eval.excluded_robots.clear()
                self.kick_eval.add_excluded_robot(opp)
                for r in main.our_robots():
                    self.kick_eval.add_excluded_robot(r)

                point, shotChance = self.kick_eval.eval_pt_to_our_goal(opp.pos)

                # Note: 0.5 is a bullshit value
                threats.append((opp.pos, 0.5 * shotChance, opp))

        # Prevent threats from being below our goal line (causes incorrect pos)
        def _adjust_pt(threat):
            pt = threat[0]
            pt.y = max(pt.y, 0.1)
            return (pt, ) + threat[1:]

        threats = list(map(_adjust_pt, threats))

        return threats
예제 #38
0
def find_gap(target_pos=constants.Field.TheirGoalSegment.center(), max_shooting_angle=60, robot_offset=8, dist_from_point=.75):
    if (not main.ball().valid):
        return target_pos

    # Find the hole in the defenders to kick at
    # The limit is 20 cm so any point past it should be defenders right there
    win_eval = robocup.WindowEvaluator(main.system_state())

    # 500 cm min circle distance plus the robot width
    test_distance = dist_from_point + constants.Robot.Radius

    # +- max offset to dodge ball
    max_angle = max_shooting_angle * constants.DegreesToRadians

    # How much left and right of a robot to give
    # Dont make this too big or it will always go far to the right or left of the robots
    robot_angle_offset = robot_offset * constants.DegreesToRadians

    zero_point = robocup.Point(0, 0)

    # Limit the angle so as we get closer, we dont miss the goal completely as much
    goal_vector = target_pos - main.ball().pos
    max_length_vector = robocup.Point(constants.Field.Length, constants.Field.Width)
    goal_limit = (goal_vector.mag() / max_length_vector.mag()) * max_angle

    # Limit on one side so we dont directly kick out of bounds
    # Add in the angle from the sideline to the target
    field_limit = (1 - abs(main.ball().pos.x) / (constants.Field.Width / 2)) * max_angle
    field_limit = field_limit + goal_vector.angle_between(robocup.Point(0, 1))

    # Limit the angle based on the opponent robots to try and always minimize the
    left_robot_limit = 0
    right_robot_limit = 0

    for robot in main.their_robots():
        ball_to_bot = robot.pos - main.ball().pos

        # Add an extra radius as wiggle room
        # kick eval already deals with the wiggle room so it isn't needed there
        if (ball_to_bot.mag() <= test_distance + constants.Robot.Radius):
            angle = goal_vector.angle_between(ball_to_bot)

            # Try and rotate onto the goal vector
            # if we actually do, then the robot is to the right of the ball vector
            ball_to_bot.rotate(zero_point, angle)
            if (ball_to_bot.angle_between(goal_vector) < 0.01):
                right_robot_limit = max(right_robot_limit, angle + robot_angle_offset)
            else:
                left_robot_limit = max(left_robot_limit, angle + robot_angle_offset)
        else:
            win_eval.add_excluded_robot(robot)


    # Angle limit on each side of the bot->goal vector
    left_angle = max_angle
    right_angle = max_angle

    # Make sure we limit the correct side due to the field
    if main.ball().pos.x < 0:
        left_angle = min(left_angle, field_limit)
    else:
        right_angle = min(right_angle, field_limit)

    # Limit due to goal
    left_angle = min(left_angle, goal_limit)
    right_angle = min(right_angle, goal_limit)

    # Limit to just over the robots
    if (left_robot_limit is not 0):
        left_angle = min(left_angle, left_robot_limit)
    if (right_robot_limit is not 0):
        right_angle = min(right_angle, right_robot_limit)

    # Get the angle that we need to rotate the target angle behind the defenders
    # since kick eval doesn't support a nonsymmetric angle around a target
    rotate_target_angle = (left_angle + -right_angle)/2
    target_width = (left_angle + right_angle)

    target_point = goal_vector.normalized() * test_distance
    target_point.rotate(zero_point, rotate_target_angle)

    windows, window = win_eval.eval_pt_to_pt(main.ball().pos, target_point + main.ball().pos, target_width)

    # Test draw points
    target_point.rotate(zero_point, target_width/2)
    p1 = target_point + main.ball().pos
    target_point.rotate(zero_point, -target_width)
    p2 = target_point + main.ball().pos
    p3 = main.ball().pos
    main.system_state().draw_polygon([p1, p2, p3], (0, 0, 255), "Free Kick search zone")


    is_opponent_blocking = False

    for robot in main.their_robots():
        if (goal_vector.dist_to(robot.pos) < constants.Robot.Radius and
            (main.ball().pos - robot.pos).mag() < test_distance):
            is_opponent_blocking = True

    # Vector from ball position to the goal
    ideal_shot = (target_pos - main.ball().pos).normalized()

    # If on our side of the field and there are enemy robots around us,
    # prioritize passing forward vs passing towards their goal
    # Would have to change this if we are not aiming for their goal
    if main.ball().pos.y < constants.Field.Length / 2 and len(windows) > 1:
        ideal_shot = robocup.Point(0, 1)

    main.system_state().draw_line(robocup.Line(main.ball().pos, target_pos), (0, 255, 0), "Target Point")

    # Weights for determining best shot
    k1 = 1.5 # Weight of closeness to ideal shot
    k2 = 1 # Weight of shot chance

    # Iterate through all possible windows to find the best possible shot
    if windows:
        best_shot = window.segment.center()
        best_weight = 0
        for wind in windows:
            pos_to_wind = (wind.segment.center() - main.ball().pos).normalized()
            dot_prod = pos_to_wind.dot(ideal_shot)
            weight = k1 * dot_prod + k2 * wind.shot_success
            if weight > best_weight:
                best_weight = weight
                best_shot = wind.segment.center()

        main.system_state().draw_line(robocup.Line(main.ball().pos, best_shot), (255, 255, 0), "Target Shot")

        best_shot = robocup.Point(0,1) + main.ball().pos
        return best_shot
    else:
        return constants.Field.TheirGoalSegment.center()
예제 #39
0
    def execute_running(self):
        super().execute_running()
        striker = self.subbehavior_with_name('striker')
        support1 = self.subbehavior_with_name('support1')
        support2 = self.subbehavior_with_name('support2')
        supports = [support1, support2]

        # project ball location a bit into the future
        ball_proj = evaluation.ball.predict(main.ball().pos,
                                            main.ball().vel,
                                            t=0.75)

        # find closest opponent to striker
        closest_dist_to_striker, closest_opp_to_striker = float("inf"), None
        if striker.robot != None:
            for opp in main.their_robots():
                d = opp.pos.dist_to(striker.robot.pos)
                if d < closest_dist_to_striker:
                    closest_dist_to_striker, closest_opp_to_striker = d, opp

        striker_engaged = striker.robot != None and closest_dist_to_striker < Basic122.SupportBackoffThresh

        # pick out which opponents our defenders should 'mark'
        # TODO: explain
        nrOppClose = 0
        bestOpp1, bestOpp2 = None, None
        bestDistSq1, bestDistSq2 = float("inf"), float("inf")
        for opp in main.their_robots():
            # use dist from goal rather than just y-coord to handle corners better
            oppDistSq = opp.pos.magsq()
            if not (striker_engaged and opp == closest_opp_to_striker):
                if oppDistSq < bestDistSq1:
                    bestDistSq2, bestOpp2 = bestDistSq1, bestOpp1
                    bestDistSq1, bestOpp1 = oppDistSq, opp
                elif oppDistSq < bestDistSq2:
                    bestDistSq2, bestOpp2 = oppDistSq, opp

                if oppDistSq < constants.Field.Length**2 / 4.0:
                    nrOppClose += 1

        # handle the case of having no good robots to mark
        if bestOpp1 == None and support1.robot != None:
            support1.mark_robot = None
            support1.robot.add_text("No mark target", (255, 255, 255),
                                    "RobotText")
            if striker.robot != None:
                support1.robot.add_text("Static Support", (255, 255, 255),
                                        "RobotText")
                support_goal = striker.robot.pos
                support_goal.x *= -1.0
                if abs(support_goal.x) < 0.2:
                    support_goal.x = -1.0 if support_goal.x < 0 else 1.0

                if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
                    support_goal.y = max(support_goal.y *
                                         Basic122.OffenseSupportRatio, 0.3)
                else:
                    support_goal.y = max(support_goal.y *
                                         Basic122.DefenseSupportRatio, 0.3)

                support1.robot.move_to(support_goal)
                support1.robot.face(ball_proj)

        # sit around and do jack shit...
        # TODO: make it do something useful
        if bestOpp2 == None and support2.robot != None:
            support2.mark_robot = None
            support2.robot.add_text("No mark target", (255, 255, 255),
                                    "RobotText")
            if striker.robot != None:
                support2.robot.add_text("Static Support", (255, 255, 255),
                                        "RobotText")
                support_goal = striker.robot.pos
                support_goal.x *= -1.0
                if abs(support_goal.x) < 0.2:
                    support_goal.x = -1.0 if support_goal.x < 0 else 1.0

                if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
                    support_goal.y = max(support_goal.y *
                                         Basic122.OffenseSupportRatio, 0.3)
                else:
                    support_goal.y = max(support_goal.y *
                                         Basic122.DefenseSupportRatio, 0.3)

                support2.robot.move_to(support_goal)
                support2.robot.face(ball_proj)

        # reassign support robots' mark targets based on dist sq and hysteresis coeff
        new_dists = [bestDistSq1, bestDistSq2]
        new_bots = [bestOpp1, bestOpp2]
        for i in range(2):
            support = supports[i]
            if new_bots[i] != None:
                cur_dist_sq = (
                    support.mark_robot.pos -
                    ball_proj).magsq() if support.mark_robot else float("inf")
                if new_dists[i] < cur_dist_sq * Basic122.MarkHysteresisCoeff:
                    support.mark_robot = new_bots[i]

        # if the supports are farther from the ball, they can mark further away
        if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
            for support in supports:
                support.ratio = Basic122.OffenseSupportRatio
        else:
            for support in supports:
                support.ratio = Basic122.DefenseSupportRatio

            # raise NotImplementedError("Make support robots avoid the shot channel")
            # FROM C++:
            # Polygon shot_obs;
            # shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length));
            # shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length));
            # shot_obs.vertices.push_back(ballProj);

            # TODO: this would be a good place for a "keep-trying container behavior"
            # make the kicker try again if it already kicked
        if not striker.is_in_state(behavior.Behavior.State.running):
            striker.restart()
예제 #40
0
 def on_enter_running(self):
     b = skills.goalside_mark.Goalside_Mark()
     b.mark_robot = main.their_robots()[0]
     self.add_subbehavior(b, name='goalside mark', required=True)
예제 #41
0
def find_gap(target_pos=constants.Field.TheirGoalSegment.center(), max_shooting_angle=60, robot_offset=8, dist_from_point=.75):
    if (not main.ball().valid):
        return target_pos

    # Find the hole in the defenders to kick at
    # The limit is 20 cm so any point past it should be defenders right there
    win_eval = robocup.WindowEvaluator(main.system_state())

    # 500 cm min circle distance plus the robot width
    test_distance = dist_from_point + constants.Robot.Radius

    # +- max offset to dodge ball
    max_angle = max_shooting_angle * constants.DegreesToRadians

    # How much left and right of a robot to give
    # Dont make this too big or it will always go far to the right or left of the robots
    robot_angle_offset = robot_offset * constants.DegreesToRadians

    zero_point = robocup.Point(0, 0)

    # Limit the angle so as we get closer, we dont miss the goal completely as much
    goal_vector = target_pos - main.ball().pos
    max_length_vector = robocup.Point(constants.Field.Length, constants.Field.Width)
    goal_limit = (goal_vector.mag() / max_length_vector.mag()) * max_angle

    # Limit on one side so we dont directly kick out of bounds
    # Add in the angle from the sideline to the target
    field_limit = (1 - abs(main.ball().pos.x) / (constants.Field.Width / 2)) * max_angle
    field_limit = field_limit + goal_vector.angle_between(robocup.Point(0, 1))

    # Limit the angle based on the opponent robots to try and always minimize the
    left_robot_limit = 0
    right_robot_limit = 0

    for robot in main.their_robots():
        ball_to_bot = robot.pos - main.ball().pos

        # Add an extra radius as wiggle room
        # kick eval already deals with the wiggle room so it isn't needed there
        if (ball_to_bot.mag() <= test_distance + constants.Robot.Radius):
            angle = goal_vector.angle_between(ball_to_bot)

            # Try and rotate onto the goal vector
            # if we actually do, then the robot is to the right of the ball vector
            ball_to_bot.rotate(zero_point, angle)
            if (ball_to_bot.angle_between(goal_vector) < 0.01):
                right_robot_limit = max(right_robot_limit, angle + robot_angle_offset)
            else:
                left_robot_limit = max(left_robot_limit, angle + robot_angle_offset)
        else:
            win_eval.add_excluded_robot(robot)


    # Angle limit on each side of the bot->goal vector
    left_angle = max_angle
    right_angle = max_angle

    # Make sure we limit the correct side due to the field
    if main.ball().pos.x < 0:
        left_angle = min(left_angle, field_limit)
    else:
        right_angle = min(right_angle, field_limit)

    # Limit due to goal
    left_angle = min(left_angle, goal_limit)
    right_angle = min(right_angle, goal_limit)

    # Limit to just over the robots
    if (left_robot_limit is not 0):
        left_angle = min(left_angle, left_robot_limit)
    if (right_robot_limit is not 0):
        right_angle = min(right_angle, right_robot_limit)

    # Get the angle that we need to rotate the target angle behind the defenders
    # since kick eval doesn't support a nonsymmetric angle around a target
    rotate_target_angle = (left_angle + -right_angle)/2
    target_width = (left_angle + right_angle)

    target_point = goal_vector.normalized() * test_distance
    target_point.rotate(zero_point, rotate_target_angle)

    windows, window = win_eval.eval_pt_to_pt(main.ball().pos, target_point + main.ball().pos, target_width)

    # Test draw points
    target_point.rotate(zero_point, target_width/2)
    p1 = target_point + main.ball().pos
    target_point.rotate(zero_point, -target_width)
    p2 = target_point + main.ball().pos
    p3 = main.ball().pos
    main.system_state().draw_polygon([p1, p2, p3], (0, 0, 255), "Free Kick search zone")


    is_opponent_blocking = False

    for robot in main.their_robots():
        if (goal_vector.dist_to(robot.pos) < constants.Robot.Radius and
            (main.ball().pos - robot.pos).mag() < test_distance):
            is_opponent_blocking = True

    # Vector from ball position to the goal
    ideal_shot = (target_pos - main.ball().pos).normalized()

    # If on our side of the field and there are enemy robots around us,
    # prioritize passing forward vs passing towards their goal
    # Would have to change this if we are not aiming for their goal
    if main.ball().pos.y < constants.Field.Length / 2 and len(windows) > 1:
        ideal_shot = robocup.Point(0, 1)

    main.system_state().draw_line(robocup.Line(main.ball().pos, target_pos), (0, 255, 0), "Target Point")

    # Weights for determining best shot
    k1 = 1.5 # Weight of closeness to ideal shot
    k2 = 1 # Weight of shot chance

    # print("ideal shot:", ideal_shot)
    # print("number of windows:", len(windows))
    # Iterate through all possible windows to find the best possible shot
    if windows:
        best_shot = window.segment.center()
        best_weight = 0
        for wind in windows:
            pos_to_wind = (wind.segment.center() - main.ball().pos).normalized()
            dot_prod = pos_to_wind.dot(ideal_shot)
            # print("weighted dot product:", dot_prod)
            # print("weighted shot chance:", wind.shot_success)
            weight = k1 * dot_prod + k2 * wind.shot_success
            if weight > best_weight:
                best_weight = weight
                best_shot = wind.segment.center()

        main.system_state().draw_line(robocup.Line(main.ball().pos, best_shot), (255, 255, 0), "Target Shot")

        best_shot = robocup.Point(0,1) + main.ball().pos
        return best_shot
    else:
        return constants.Field.TheirGoalSegment.center()
예제 #42
0
    def execute_running(self):
        striker = self.subbehavior_with_name('striker')
        support1 = self.subbehavior_with_name('support1')
        support2 = self.subbehavior_with_name('support2')
        supports = [support1, support2]


        # project ball location a bit into the future
        ball_proj = evaluation.ball.predict(main.ball().pos, main.ball().vel, t=0.75)


        # find closest opponent to striker
        closest_dist_to_striker, closest_opp_to_striker = float("inf"), None
        if striker.robot != None:
            for opp in main.their_robots():
                d = opp.pos.dist_to(striker.robot.pos)
                if d < closest_dist_to_striker:
                    closest_dist_to_striker, closest_opp_to_striker = d, opp

        striker_engaged = striker.robot != None and closest_dist_to_striker < Basic122.SupportBackoffThresh


        # pick out which opponents our defenders should 'mark'
        # TODO: explain
        nrOppClose = 0
        bestOpp1, bestOpp2 = None, None
        bestDistSq1, bestDistSq2 = float("inf"), float("inf")
        for opp in main.their_robots():
            # use dist from goal rather than just y-coord to handle corners better
            oppDistSq = opp.pos.magsq()
            if not (striker_engaged and opp == closest_opp_to_striker):
                if oppDistSq < bestDistSq1:
                    bestDistSq2, bestOpp2 = bestDistSq1, bestOpp1
                    bestDistSq1, bestOpp1 = oppDistSq, opp
                elif oppDistSq < bestDistSq2:
                    bestDistSq2, bestOpp2 = oppDistSq, opp

                if oppDistSq < constants.Field.Length**2 / 4.0:
                    nrOppClose += 1


        # handle the case of having no good robots to mark
        if bestOpp1 == None and support1.robot != None:
            support1.mark_robot = None
            support1.robot.add_text("No mark target", (255,255,255), "RobotText")
            if striker.robot != None:
                support1.robot.add_text("Static Support", (255,255,255), "RobotText")
                support_goal = striker.robot.pos
                support_goal.x *= -1.0
                if abs(support_goal.x) < 0.2:
                    support_goal.x = -1.0 if support_goal.x < 0 else 1.0

                if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
                    support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3)
                else:
                    support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3)

                support1.robot.move_to(support_goal)
                support1.robot.face(ball_proj)

        # sit around and do jack shit...
        # TODO: make it do something useful
        if bestOpp2 == None and support2.robot != None:
            support2.mark_robot = None
            support2.robot.add_text("No mark target", (255,255,255), "RobotText")
            if striker.robot != None:
                support2.robot.add_text("Static Support", (255,255,255), "RobotText")
                support_goal = striker.robot.pos
                support_goal.x *= -1.0
                if abs(support_goal.x) < 0.2:
                    support_goal.x = -1.0 if support_goal.x < 0 else 1.0

                if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
                    support_goal.y = max(support_goal.y * Basic122.OffenseSupportRatio, 0.3)
                else:
                    support_goal.y = max(support_goal.y * Basic122.DefenseSupportRatio, 0.3)

                support2.robot.move_to(support_goal)
                support2.robot.face(ball_proj)

        # reassign support robots' mark targets based on dist sq and hysteresis coeff
        new_dists = [bestDistSq1, bestDistSq2]
        new_bots = [bestOpp1, bestOpp2]
        for i in range(2):
            support = supports[i]
            if new_bots[i] != None:
                cur_dist_sq = (support.mark_robot.pos - ball_proj).magsq() if support.mark_robot else float("inf")
                if new_dists[i] < cur_dist_sq * Basic122.MarkHysteresisCoeff:
                    support.mark_robot = new_bots[i]


        # if the supports are farther from the ball, they can mark further away
        if ball_proj.y > constants.Field.Length / 2.0 and nrOppClose > 0:
            for support in supports: support.ratio = Basic122.OffenseSupportRatio
        else:
            for support in supports: support.ratio = Basic122.DefenseSupportRatio


        # keep support robots away from the striker
        if striker.robot != None:
            for supp in [support1, support2]:
                if supp.robot != None:
                    supp.robot.set_avoid_teammate_radius(striker.robot.shell_id(), Basic122.SupportAvoidTeammateRadius)

            # raise NotImplementedError("Make support robots avoid the shot channel")
            # FROM C++:
            # Polygon shot_obs;
            # shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length));
            # shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length));
            # shot_obs.vertices.push_back(ballProj);


        # TODO: this would be a good place for a "keep-trying container behavior"
        # make the kicker try again if it already kicked
        if not striker.is_in_state(behavior.Behavior.State.running):
            striker.restart()
예제 #43
0
 def has_ball(self):
     closeIndicator = False
     for r in main.their_robots():
         closeIndicator = closeIndicator or (
             r.pos - main.ball().pos).mag() < self.ball_lost_distance
     return closeIndicator