Beispiel #1
0
def _optimal_defender_pos(state) -> Coordinate:
    side = 1 if state.world_view.side == 'l' else -1
    ball: Coordinate = state.world_view.ball.get_value().coord
    play_position = state.get_global_play_pos()
    ball_delta_y = ball.pos_y - play_position.pos_y
    ball_delta_x = ball.pos_x - play_position.pos_x

    # Position player according to their starting position and the current ball position
    optimal_x = play_position.pos_x + ball_delta_x * 0.4 + ball.pos_x * 0.4
    if side > 0:
        optimal_x = clamp(optimal_x, -45, -3)
    else:
        optimal_x = clamp(optimal_x, 3, 45)

    # Used to make players position themselves closer to the goal on the y-axis when far up/down the field
    y_goal_factor = 1 - (abs(optimal_x) -
                         35) * 0.05 if abs(optimal_x) > 35 else 1.0
    optimal_y = clamp(
        play_position.pos_y + ball.pos_y * 0.4 + ball_delta_y * 0.1, -25,
        25) * y_goal_factor

    if state.world_view.team_has_ball(state.team_name, max_data_age=4):
        return Coordinate(optimal_x + (10 * side), optimal_y)

    return Coordinate(optimal_x, optimal_y)
Beispiel #2
0
 def get_global_play_pos(self):
     if self.world_view.side == "l":
         return Coordinate(self.playing_position.pos_x,
                           -self.playing_position.pos_y)
     else:
         return Coordinate(-self.playing_position.pos_x,
                           self.playing_position.pos_y)
Beispiel #3
0
def _optimal_midfielder_pos(state) -> Coordinate:
    side = 1 if state.world_view.side == 'l' else -1
    if not state.world_view.ball.is_value_known():
        return state.get_global_play_pos()
    ball: Coordinate = state.world_view.ball.get_value().coord
    play_position = state.get_global_play_pos()
    ball_delta_y = ball.pos_y - play_position.pos_y
    ball_delta_x = ball.pos_x - play_position.pos_x

    # Position player according to their starting position and the current ball position
    if side * ball.pos_x > 0:
        # Attacking
        optimal_x = clamp(
            play_position.pos_x + ball_delta_x * 0.4 + ball.pos_x * 0.6, -45,
            45)
    else:
        # Defending
        optimal_x = clamp(play_position.pos_x + ball.pos_x * 0.4, -45, 45)

    # Used to make players position themselves closer to the goal on the y-axis when far up/down the field
    y_goal_factor = 1 - (abs(optimal_x) -
                         35) * 0.05 if abs(optimal_x) > 35 else 1.0
    optimal_y = clamp(
        play_position.pos_y + ball_delta_y * 0.2 + ball.pos_y * 0.2, -25,
        25) * y_goal_factor

    if state.world_view.team_has_ball(state.team_name, max_data_age=4):
        opt_coord = Coordinate(optimal_x + (10 * side), optimal_y)
        free_pos = state.get_closest_free_position(opt_coord)
        if state.is_test_player():
            debug_msg("Free position:{0}".format(free_pos), "FREE_POSITION")
        return opt_coord if free_pos is None else free_pos

    return Coordinate(optimal_x, optimal_y)
Beispiel #4
0
 def test__calculate_ball_global_dir(self):
     self.skipTest("Ball no longer has 'last_position' attribute")
     state: PlayerState = PlayerState()
     state.body_angle.set_value(90, 1)
     ball: Ball = Ball(0, 0, Coordinate(-1.5, 1.5), 0)
     ball.last_position.set_value(Coordinate(0, 0), 0)
     state.world_view.ball.set_value(ball, 1)
     stop_ball(state)
Beispiel #5
0
 def is_approaching_goal(self):
     if self.position.is_value_known():
         pos: Coordinate = self.position.get_value()
         if self.world_view.side == "l" and pos.euclidean_distance_from(
                 Coordinate(52.5, 0)) < APPROA_GOAL_DISTANCE:
             return True
         if self.world_view.side == "r" and pos.euclidean_distance_from(
                 Coordinate(-52.5, 0)) < APPROA_GOAL_DISTANCE:
             return True
     return False
Beispiel #6
0
    def test_trilateration_horizontally_aligned_both_negative(self):
        expected_position = Coordinate(-20, 10)
        flag_one = parsing.Flag("", Coordinate(-40, 0.0), 22.36, 0)
        flag_two = parsing.Flag("", Coordinate(-10, 0.0), 14.14, 0)

        (first_solution,
         second_solution) = parsing._solve_trilateration(flag_one, flag_two)
        first_solution_correct = is_same_coordinate(first_solution,
                                                    expected_position)
        second_solution_correct = is_same_coordinate(second_solution,
                                                     expected_position)

        self.assertTrue(first_solution_correct or second_solution_correct)
Beispiel #7
0
    def test_trilateration_horizontally_misaligned_negative_and_positive(self):
        expected_position = Coordinate(0, -5)
        flag_one = parsing.Flag("", Coordinate(5, 5), 11.1803398875, 0)
        flag_two = parsing.Flag("", Coordinate(-15, -10), 15.8113883008, 0)

        (first_solution,
         second_solution) = parsing._solve_trilateration(flag_one, flag_two)
        first_solution_correct = is_same_coordinate(first_solution,
                                                    expected_position)
        second_solution_correct = is_same_coordinate(second_solution,
                                                     expected_position)

        self.assertTrue(first_solution_correct or second_solution_correct)
Beispiel #8
0
    def test_trilateration_order_reversed(self):
        flag_one = parsing.Flag("", Coordinate(0, 0), 11.5, 0)
        flag_two = parsing.Flag("", Coordinate(30, 0), 21.5, 0)

        result_1 = parsing._solve_trilateration(flag_one, flag_two)
        result_2 = parsing._solve_trilateration(flag_two, flag_one)

        self.assertTrue(
            is_same_coordinate(result_1[0], result_2[0])
            or is_same_coordinate(result_1[0], result_2[1]))
        self.assertTrue(
            is_same_coordinate(result_1[1], result_2[0])
            or is_same_coordinate(result_1[1], result_2[1]))
Beispiel #9
0
    def test_trilateration_horizontally_aligned(self):
        expected_position = Coordinate(19.53533, 21.47515)
        flag_one = parsing.Flag("", Coordinate(10, 15), 11.5, 0)
        flag_two = parsing.Flag("", Coordinate(40, 15), 21.5, 0)

        (first_solution,
         second_solution) = parsing._solve_trilateration(flag_one, flag_two)
        first_solution_correct = is_same_coordinate(first_solution,
                                                    expected_position)
        second_solution_correct = is_same_coordinate(second_solution,
                                                     expected_position)

        self.assertTrue(first_solution_correct or second_solution_correct)
Beispiel #10
0
    def test_get_closest_ordered_opponents(self):
        wv = WorldViewCoach(0, "Team1")
        wv.ball = BallOnlineCoach(Coordinate(0, 0), 0, 0)
        for team in ["Team1", "Team2"]:
            for num in range(0, 11):
                wv.players.append(
                    PlayerViewCoach(team, str(num), False,
                                    Coordinate(num, num), 0, 0, 0, 0, False))

        closest_team_members = wv.get_closest_team_players_to_ball(5)
        closest_opponents = wv.get_closest_opponents(closest_team_members, 5)

        for i in range(0, 5):
            self.assertEqual(i, closest_opponents[i].num)
Beispiel #11
0
    def is_near(self, coordinate: Coordinate, allowed_delta=0.5):
        if not self.position.is_value_known():
            return False

        distance = coordinate.euclidean_distance_from(
            self.position.get_value())
        return distance <= allowed_delta
Beispiel #12
0
 def test_calculate_kick_power_01(self):
     self.skipTest("Revised calculate_power function")
     ball = Ball(0.7, 180, Coordinate(0, 0), 0)
     ps = PlayerState()
     ps.world_view.ball.set_value(ball, 0)
     distance = 17
     self.assertTrue(_calculate_kick_power(ps, distance) > 100, "Should not be able to kick 17 meters with worst "
                                                               "case ball position")
Beispiel #13
0
 def test_calculate_kick_power_03(self):
     self.skipTest("Revised calculate_power function")
     ball = Ball(0.4, 90, Coordinate(0, 0), 0)
     ps = PlayerState()
     ps.world_view.ball.set_value(ball, 0)
     distance = 30
     self.assertTrue(_calculate_kick_power(ps, distance) < 100, "Should be able to kick 30 meters with"
                                                               " decent ball position")
Beispiel #14
0
 def test_calculate_kick_power_02(self):
     self.skipTest("Revised calculate_power function")
     ball = Ball(0, 0, Coordinate(0, 0), 0)
     ps = PlayerState()
     ps.world_view.ball.set_value(ball, 0)
     distance = 43
     self.assertTrue(_calculate_kick_power(ps, distance) < 100, "Should be able to kick 43 meters with optimal ball "
                                                               "position")
Beispiel #15
0
def _optimal_striker_pos(state: PlayerState) -> Coordinate:
    side = 1 if state.world_view.side == 'l' else -1
    if not state.world_view.ball.is_value_known():
        return state.get_global_play_pos()
    ball: Coordinate = state.world_view.ball.get_value().coord
    play_position = state.get_global_play_pos()
    ball_delta_y = ball.pos_y - play_position.pos_y

    if side * ball.pos_x > 0:
        # Attacking
        x_offset = ball.pos_x + side * 5
        optimal_x = clamp(play_position.pos_x + x_offset, -45, 45)

        # Used to make players position themselves closer to the goal on the y-axis when far up/down the field
        y_goal_factor = 0.982888 + 0.002871167 * abs(
            optimal_x) - 0.0000807057 * pow(optimal_x, 2)

        optimal_y = clamp(
            play_position.pos_y + ball.pos_y * 0.2 + ball_delta_y * 0.4, -30,
            30) * y_goal_factor

        if state.world_view.team_has_ball(state.team_name, max_data_age=4):
            opt_coord = Coordinate(optimal_x + (10 * side), optimal_y)
            free_pos = state.get_closest_free_position(opt_coord)
            if state.is_test_player():
                debug_msg("Free position:{0}".format(free_pos),
                          "FREE_POSITION")
            return opt_coord if free_pos is None else free_pos

        return Coordinate(optimal_x, optimal_y)
    else:
        # Defending
        optimal_x = -state.get_global_play_pos().pos_x + ball.pos_x * 0.4
        optimal_y = state.get_global_play_pos().pos_y + ball_delta_y * 0.2

        if state.world_view.team_has_ball(state.team_name, max_data_age=4):
            opt_coord = Coordinate(optimal_x + (10 * side), optimal_y)
            free_pos = state.get_closest_free_position(opt_coord)
            if state.is_test_player():
                debug_msg("Free position:{0}".format(free_pos),
                          "FREE_POSITION")
            return opt_coord if free_pos is None else free_pos

        return Coordinate(optimal_x, optimal_y)
Beispiel #16
0
    def test_get_closest_team_players_to_ball_00(self):
        wv = WorldViewCoach(0, "Team1")
        player1 = PlayerViewCoach("Team1", 1, False, Coordinate(10, 10), 0, 0,
                                  0, 0, False)
        player2 = PlayerViewCoach("Team1", 2, False, Coordinate(5, 5), 0, 0, 0,
                                  0, False)
        player3 = PlayerViewCoach("Team1", 3, False, Coordinate(0, 0), 0, 0, 0,
                                  0, False)
        wv.players.append(player1)
        wv.players.append(player3)
        wv.players.append(player2)
        wv.ball = BallOnlineCoach(Coordinate(0, 0), 0, 0)

        result: [PlayerViewCoach] = wv.get_closest_team_players_to_ball(3)
        self.assertEqual(len(result), 3,
                         "Amount of results should fit the argument.")
        self.assertEqual(result[0].num, 3, "Player 3 should be the closest")
        self.assertEqual(result[1].num, 2, "Player 2 should be second closest")
        self.assertEqual(result[2].num, 1, "Player 1 should be furthest away")
Beispiel #17
0
def _optimal_goalie_pos(state: PlayerState):
    if state.team_name in configurations.GOALIE_MODEL_TEAMS:
        if state.goalie_position_strategy is not None:
            optimal_coord = Coordinate(state.goalie_position_strategy.pos_x,
                                       state.goalie_position_strategy.pos_y)
            state.goalie_position_strategy = None
            return optimal_coord
        else:
            ball: Ball = state.world_view.ball.get_value()

            y_value = clamp(ball.coord.pos_y * 0.8, -5, 5)

            return Coordinate(state.get_global_start_pos().pos_x, y_value)
    else:
        ball: Ball = state.world_view.ball.get_value()

        y_value = clamp(ball.coord.pos_y * 0.8, -5, 5)

        return Coordinate(state.get_global_start_pos().pos_x, y_value)
Beispiel #18
0
    def test_get_closest_team_players_to_ball_03(self):
        wv = WorldViewCoach(0, "Team2")
        player1 = PlayerViewCoach("Team1", 1, False, Coordinate(10, 10), 0, 0,
                                  0, 0, False)
        player2 = PlayerViewCoach("Team1", 2, False, Coordinate(5, 5), 0, 0, 0,
                                  0, False)
        player3 = PlayerViewCoach("Team2", 3, False, Coordinate(100, 100), 0,
                                  0, 0, 0, False)

        wv.players.append(player1)
        wv.players.append(player3)
        wv.players.append(player2)
        wv.ball = BallOnlineCoach(Coordinate(0, 0), 0, 0)

        # take only closest player
        result: [PlayerViewCoach] = wv.get_closest_team_players_to_ball(1)
        # Player 3 is team 2, the rest should not be included
        self.assertEqual(len(result), 1,
                         "Amount of results should fit the argument")
        self.assertEqual(result[0].num, 3, "Player 3 should be the closest")
Beispiel #19
0
    def position_player(self):
        if (len(goalie_pos) + len(defenders_pos) + len(midfielders_pos) +
                len(strikers_pos)) > 11:
            raise Exception(
                "Too many startup positions given. Expected < 12, got: " + str(
                    len(goalie_pos) + len(defenders_pos) +
                    len(midfielders_pos) + len(strikers_pos)))

        self.assign_position()
        if self.player_state.player_type == "goalie":
            if len(goalie_pos) > 1:
                raise Exception("Only 1 goalie / goalie position allowed")
            pos = goalie_pos[0]
            move_action = "(move {0} {1})".format(pos[0], pos[1])
            self.player_state.playing_position = Coordinate(pos[0], pos[1])
        elif self.player_state.player_type == "defender":
            index = self.player_state.num - 1 - len(goalie_pos)
            pos = defenders_pos[index]
            self.player_state.playing_position = Coordinate(pos[0], pos[1])
            move_action = "(move {0} {1})".format(pos[0], pos[1])
        elif self.player_state.player_type == "midfield":
            index = self.player_state.num - 1 - len(goalie_pos) - len(
                defenders_pos)
            pos = midfielders_pos[index]
            self.player_state.playing_position = Coordinate(
                pos[0] + 10, pos[1])
            move_action = "(move {0} {1})".format(pos[0], pos[1])
        elif self.player_state.player_type == "striker":
            index = self.player_state.num - 1 - len(goalie_pos) - len(
                defenders_pos) - len(midfielders_pos)
            pos = strikers_pos[index]
            self.player_state.playing_position = Coordinate(
                pos[0] + 10, pos[1])
            move_action = "(move {0} {1})".format(pos[0], pos[1])
        else:
            raise Exception("Could not position player: " +
                            str(self.player_state))
        self.player_state.starting_position = Coordinate(pos[0], pos[1])
        self.player_state.objective_behaviour = pos[2]
        self.player_conn.action_queue.put(move_action)
        self.is_positioned = True
Beispiel #20
0
    def can_player_reach(self, position: Coordinate, ticks):
        distance = position.euclidean_distance_from(self.position.get_value())
        extra_time = 1

        if distance <= KICKABLE_MARGIN:
            return True

        if not self.body_facing(position, delta=5):
            extra_time += 1
            if self.body_state.speed > 0.2:
                extra_time += 1

        return self.time_to_rush_distance(distance) <= ticks + extra_time
Beispiel #21
0
def _dribble_objective(state: PlayerState):
    side = 1 if state.world_view.side == "l" else -1
    if not state.is_nearest_ball(1):
        state.mode = DEFAULT_MODE
        return determine_objective(state)

    if not state.is_near_ball(KICKABLE_MARGIN):
        return _rush_to_ball_objective(state)

    pos: Coordinate = state.position.get_value()
    if pos.euclidean_distance_from(Coordinate(52.5 * side, 0)) < 24:
        return Objective(
            state,
            lambda: actions.shoot_to(state, Coordinate(55 * side, 0), 100),
            lambda: True, 1)

    should_dribble = state.received_dribble_instruction.get_value() \
                     and state.received_dribble_instruction.last_updated_time >= state.now() - 100

    if not should_dribble:
        target = _choose_pass_target(state)
        if target is not None:
            return Objective(state,
                             lambda: actions.pass_to_player(state, target),
                             lambda: True, 1)
    else:
        state.received_dribble_instruction.set_value(False, state.now())

    if state.is_near_ball(
    ):  # todo temp: and state.action_history.has_looked_for_targets:
        target_coord: Coordinate = Coordinate(52.5 * side, 0)
        opposing_goal_dir = math.degrees(
            calculate_full_origin_angle_radians(target_coord,
                                                state.position.get_value()))
        state.action_history.has_looked_for_targets = False
        return Objective(
            state, lambda: actions.dribble(state, int(opposing_goal_dir)),
            lambda: False, 1)
    return _rush_to_ball_objective(state)
Beispiel #22
0
def determine_objective_biptest(state: PlayerState):
    # If lost orientation -> blind orient
    if _lost_orientation(state):
        return Objective(state, lambda: actions.blind_orient(state),
                         lambda: True, 1)

    # If ball unknown -> locate ball
    if _ball_unknown(state):
        return Objective(state, lambda: actions.locate_ball(state),
                         lambda: True, 1)

    if state.position.is_value_known():
        side: int = 1 if state.world_view.side == "l" else -1
        lower_goal: Coordinate = Coordinate(-25 * side, -33)
        upper_goal: Coordinate = Coordinate(-25 * side, 33)
        if not state.is_near(upper_goal, 2):
            debug_msg("Going to left goal", "BIPTEST")
            return Objective(state, lambda: actions.rush_to(state, upper_goal),
                             lambda: state.is_near(upper_goal, 0.5), 1000)
        else:
            debug_msg("Going to right goal", "BIPTEST")
            return Objective(state, lambda: actions.rush_to(state, lower_goal),
                             lambda: state.is_near(lower_goal, 0.5), 1000)
Beispiel #23
0
 def __init__(self) -> None:
     self.turn_history = ViewFrequency()
     self.ball_focus_actions = 0
     self.last_see_update = 0
     self.last_catch = 0
     self.two_see_updates_ago = 0
     self.three_see_updates_ago = 0
     self.has_just_intercept_kicked = False
     self.turn_in_progress = False
     self.missed_turn_last_see = False
     self.expected_speed = None
     self.projected_position = Coordinate(0, 0)
     self.has_looked_for_targets = False
     self.expected_angle_change = 0
     self.expected_body_angle = None
     self.last_look_for_pass_targets = 0
     self.last_stamina_strat_generated = 0
     self.dashes_last_stamina_strat = 0
     self.intercepting = False
Beispiel #24
0
def determine_objective_goalie_positioning_striker(state: PlayerState):
    # If lost orientation -> blind orient
    if _lost_orientation(state):
        return Objective(state, lambda: actions.blind_orient(state),
                         lambda: True, 1)

    # If ball unknown -> locate ball
    if _ball_unknown(state):
        return Objective(state, lambda: actions.locate_ball(state),
                         lambda: True, 1)

    side = 1 if state.world_view.side == "l" else -1
    if state.world_view.sim_time > 75 and len(state.coach_commands) > 0:
        # First check for dribble, and dribble if needed
        dribble_in_commands: bool = False
        for command in state.coach_commands:
            cmd = command.get_value()
            if "dribble" in cmd and not state.goalie_position_strat_have_dribbled:
                dribble_in_commands = True
                dribble_dir = int(str(cmd).replace("(dribble ", "")[:-1])
                state.goalie_position_strat_have_dribbled = True
                return Objective(
                    state, lambda: actions.dribble(
                        state, int(dribble_dir), dribble_kick_power=20),
                    lambda: True, 1)

        # If already dribble or should not dribble
        if not dribble_in_commands or state.goalie_position_strat_have_dribbled:
            if not state.is_near_ball():
                return _rush_to_ball_objective(state)

            if state.world_view.sim_time > 75:
                for command in state.coach_commands:
                    cmd = command.get_value()
                    if "striker_target_y" in cmd:
                        target_y_value = int(cmd[cmd.index(" ") + 1:-1])

                return Objective(
                    state, lambda: actions.shoot_to(
                        state, Coordinate(55 * side, target_y_value), 75),
                    lambda: True, 1)

    return Objective(state, lambda: [], lambda: True, 1)
Beispiel #25
0
    def get_closest_free_position(self,
                                  opt_coord: Coordinate,
                                  max_delta_from_org_coord=5,
                                  min_delta_from_opp=7):
        init_x: int = int(opt_coord.pos_x)
        init_y: int = int(opt_coord.pos_y)

        free_cords: [Coordinate] = []

        for x in range(init_x, init_x + max_delta_from_org_coord):
            for y in range(init_y, init_y + max_delta_from_org_coord):
                c: Coordinate = Coordinate(x, y)
                if self.is_coord_free(c, min_delta_from_opp):
                    free_cords.append(c)

        debug_msg(
            "Opt_coord={0}, free_coords={1}".format(opt_coord, free_cords),
            "FREE_POSITION")
        if len(free_cords) > 0:
            return sorted(free_cords,
                          key=lambda c: c.euclidean_distance_from(opt_coord),
                          reverse=False)[0]

        return None
Beispiel #26
0
def _choose_pass_target(state: PlayerState, must_pass: bool = False):
    print("choose pass target")
    """
    If uppaal has been generated recently -> Follow strat if applicable
    If free targets forward -> Pass forward
    If no free targets forward, but i am not marked -> dribble forward
    If no free targets forward, but free targets behind, and i am marked -> Pass back
    If no free targets and i am marked -> Try to dribble anyway
    :return: Parse target or None, if dribble
    """

    # For pass chain model, if an existing target is seen by player, pass ball
    if len(state.passchain_targets) > 0:
        print("passchain longer than 0")
        for target in state.passchain_targets:
            target: PrecariousData
            if target.last_updated_time > state.now() - 40:
                print("if target update time is later than 40 seconds ago")
                target = state.find_teammate_closest_to(target.get_value(),
                                                        max_distance_delta=8.0)
                if target is not None:
                    print("TORGET ACQUIRED : ", target)
                    return target

    debug_msg(str(state.now()) + "Choosing pass target", "DRIBBLE_PASS_MODEL")
    # Act according to Possession model
    if state.dribble_or_pass_strat.is_value_known():
        if state.dribble_or_pass_strat.is_value_known(state.now() - 8):
            debug_msg(
                "Following uppaal DribbleOrPass strategy :" +
                str(state.dribble_or_pass_strat.get_value()),
                "DRIBBLE_PASS_MODEL")
            strat = state.dribble_or_pass_strat.get_value()
            state.dribble_or_pass_strat = PrecariousData.unknown()
            if DRIBBLE_INDICATOR in strat:
                if not must_pass:
                    state.statistics.use_possession_strategy()
                    debug_msg(
                        str(state.now()) + " Dribble!", "DRIBBLE_PASS_MODEL")
                    return None

            else:
                match = re.match(r'.*\(([^,]*), ([^)]*)\)', strat)
                x = float(match.group(1))
                y = float(match.group(2))
                target = state.find_teammate_closest_to(Coordinate(x, y),
                                                        max_distance_delta=3.0)
                if target is not None:
                    debug_msg(
                        str(state.now()) +
                        " DRIBBLE_PASS_MODEL : Playing to :" +
                        str(Coordinate(x, y)), "DRIBBLE_PASS_MODEL")

                    # If target is outside the no no square then return target
                    i = -1 if state.world_view.side == "l" else 1
                    is_too_far_back = True if (state.world_view.side == "l" and target.coord.pos_x < -36) \
                                              or (state.world_view.side == "r" and target.coord.pos_x > 36) else False

                    if (not is_too_far_back) and (not is_offside(
                            state, target)) and (target.coord.pos_y > -20
                                                 or target.coord.pos_y > 20):
                        state.statistics.use_possession_strategy()
                        return target
                else:
                    debug_msg(
                        str(state.now()) + "No teammate matched :" +
                        str(Coordinate(x, y)) + " Visible: " +
                        str(state.world_view.get_teammates(
                            state.team_name, 10)), "DRIBBLE_PASS_MODEL")

        # Discard strategy
        state.statistics.discard_possession_strategy()
        state.dribble_or_pass_strat = PrecariousData.unknown()

    side = state.world_view.side
    """ # TODO : TESTING ONLY ----------------------------------------------------------
    teammates = state.world_view.get_teammates(state.team_name, 2)
    if len(teammates) is not 0:
        return choice(teammates)
    # todo -------------------------------------------------------------------------- """

    am_i_marked = state.world_view.is_marked(team=state.team_name,
                                             max_data_age=4,
                                             min_distance=4)

    # If free targets forward -> Pass forward
    forward_team_mates = state.world_view.get_non_offside_forward_team_mates(
        state.team_name,
        side,
        state.position.get_value(),
        max_data_age=4,
        min_distance_free=2,
        min_dist_from_me=2)

    if len(forward_team_mates) > 0:
        # If free team mates sort by closest to opposing teams goal
        opposing_team_goal: Coordinate = Coordinate(
            52.5, 0) if side == "l" else Coordinate(-52.5, 0)
        debug_msg("forward_team_mates: " + str(forward_team_mates),
                  "PASS_TARGET")
        good_target = list(
            sorted(forward_team_mates,
                   key=lambda p: p.coord.euclidean_distance_from(
                       opposing_team_goal),
                   reverse=False))[0]
        return good_target

    # If no free targets forward, but i am not marked -> dribble forward
    if len(forward_team_mates) < 1 and not am_i_marked:
        debug_msg("No free targets forward -> Dribble!", "PASS_TARGET")
        if must_pass:
            tms = state.world_view.get_teammates(state.team_name, 5)
            if len(tms) > 0:
                return random.choice(tms)
        return None

    # If no free targets forward, but free targets behind, and i am marked -> Pass back
    behind_team_mates = state.world_view.get_free_behind_team_mates(
        state.team_name,
        side,
        state.position.get_value(),
        max_data_age=3,
        min_distance_free=3,
        min_dist_from_me=3)
    if len(behind_team_mates) > 0:
        # Get the player furthest forward and free
        opposing_team_goal: Coordinate = Coordinate(
            52.5, 0) if side == "l" else Coordinate(-52.5, 0)
        debug_msg("Behind_team_mates: " + str(behind_team_mates),
                  "PASS_TARGET")
        good_target = list(
            sorted(behind_team_mates,
                   key=lambda p: p.coord.euclidean_distance_from(
                       opposing_team_goal),
                   reverse=False))[0]
        return good_target

    # If no free targets and i am marked -> Try to dribble anyway
    debug_msg("No free targets forward and i am marked -> Dribble anyway!",
              "PASS_TARGET")
    if must_pass:
        tms = state.world_view.get_player_observations(state.team_name, 3)
        if len(tms) > 0:
            return random.choice(tms)
    return None