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)
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)
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)
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)
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
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]))
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)
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)
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)
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)
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")
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")
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")
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)
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")
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)
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")
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
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)
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)
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)
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
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
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