def should_recalculate(self, state: PlayerState): # Don't recalculate if there are any un-executed urgent commands if self.has_urgent_commands() or self.has_processed_see_update: return False deadline_reached = self.deadline <= state.now() return deadline_reached or self.completion_criteria()
def __init__(self, state: PlayerState, command_generator, completion_criteria=lambda: True, maximum_duration=1) -> None: self.command_generator = command_generator self.completion_criteria = completion_criteria self.deadline = state.now() + maximum_duration self.commands_executed = 0 self.planned_commands: [Command] = [] self.last_command_update_time = -1 self.has_processed_see_update = False
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 _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
def determine_objective_field_default(state: PlayerState): state.intercepting = False # If lost orientation -> blind orient if _lost_orientation(state): return Objective(state, lambda: actions.blind_orient(state), lambda: True, 1) opponent_side = "r" if state.world_view.side == "l" else "l" # If game not started or other team starting -> Idle orientation if state.world_view.game_state == 'before_kick_off' or state.world_view.game_state == "kick_off_{0}".format( opponent_side) or "goal" in state.world_view.game_state: return Objective(state, lambda: actions.idle_orientation(state), lambda: True, 1) # If some fault has been made by our team -> position optimally if "fault_{0}".format( state.world_view.side) in state.world_view.game_state: return _position_optimally_objective(state) # If we have a free kick, corner_kick, kick_in or kick_off # If closest -> Go to ball and pass, else position optimally if state.world_view.game_state == "free_kick_{0}".format(state.world_view.side) \ or state.world_view.game_state == "corner_kick_{0}".format(state.world_view.side) \ or state.world_view.game_state == "kick_in_{0}".format(state.world_view.side) \ or state.world_view.game_state == "kick_off_{0}".format(state.world_view.side) \ or state.world_view.game_state == "offside_{0}".format(opponent_side): if _ball_unknown(state): return _locate_ball_objective(state) if state.is_near_ball(KICKABLE_MARGIN): if state.world_view.sim_time - state.action_history.last_look_for_pass_targets > 2: return Objective(state, lambda: actions.look_for_pass_target(state), lambda: True, 2) if _choose_pass_target(state, must_pass=True) is not None: return Objective( state, lambda: actions.pass_to_player( state, _choose_pass_target(state, must_pass=True)), lambda: True, 1) else: return Objective(state, lambda: actions.look_for_pass_target(state), lambda: True, 2) elif state.is_nearest_ball(1): return _jog_to_ball_objective(state) else: return _position_optimally_objective(state) # If in dribbling mode -> Dribble if state.mode is DRIBBLING_MODE: return _dribble_objective(state) # If in possession mode -> Pass if state.mode is POSSESSION_MODE: return _pass_objective(state) # If position known, but ball not -> Locate ball if _ball_unknown(state): return _locate_ball_objective(state) # If in possession of ball -> dribble! if state.is_near_ball() and state.is_nearest_ball(1): state.mode = DRIBBLING_MODE return _dribble_objective(state) required_degree = calculate_required_degree(state) if state.is_nearest_ball(required_degree): intercept_actions = actions.intercept_2(state) state.intercepting = True if intercept_actions is not None: return Objective(state, lambda: intercept_actions) else: return _rush_to_ball_objective(state) # If ball not incoming -> Position optimally while looking at ball if not state.ball_incoming() and not configurations.USING_PASS_CHAIN_STRAT: if state.is_test_player(): debug_msg(str(state.now()) + " Position optimally!", "ACTIONS") return _position_optimally_objective(state) if state.is_test_player(): debug_msg(str(state.now()) + " Idle orientation!", "ACTIONS") return Objective(state, lambda: actions.idle_orientation(state), lambda: True, 1)
def determine_objective_goalie_default(state: PlayerState): opponent_side = "r" if state.world_view.side == "l" else "l" # If goalie and goal_kick -> Go to ball and pass if state.world_view.game_state == "goal_kick_{0}".format( state.world_view.side) and state.num == 1: debug_msg( str(state.now()) + " | goal kick -> got to ball and pass", "GOALIE") if state.is_near_ball(KICKABLE_MARGIN): return _pass_objective(state, must_pass=True) else: return _jog_to_ball_objective(state) # If game not started or other team starting -> Idle orientation if state.world_view.game_state == 'before_kick_off' or state.world_view.game_state == "kick_off_{0}".format( opponent_side) or ("goal_r" == state.world_view.game_state or "goal_l" == state.world_view.game_state): debug_msg( str(state.now()) + " | If game not started or other team starting -> Idle orientation", "GOALIE") return Objective(state, lambda: actions.idle_orientation(state), lambda: True, 1) # If lost_orientation -> blind orient if _lost_orientation(state): debug_msg( str(state.now()) + " | lost orientation -> blind orient", "GOALIE") return Objective(state, lambda: actions.blind_orient(state), lambda: True, 1) # If ball unknown -> locate ball if _ball_unknown(state): debug_msg( str(state.now()) + " | ball unknown -> locate ball", "GOALIE") return Objective(state, lambda: actions.locate_ball(state), lambda: True, 1) # If some fault has been made by our team -> Position optimally if "fault_{0}".format( state.world_view.side) in state.world_view.game_state: debug_msg( str(state.now()) + " | Team made fault -> position optimally", "GOALIE") return _position_optimally_objective_goalie(state) # If we have a free kick, corner_kick, kick_in, kick_off or goal_kick # If closest -> Go to ball and pass, else position optimally if state.world_view.game_state == "free_kick_{0}".format(state.world_view.side) \ or state.world_view.game_state == "corner_kick_{0}".format(state.world_view.side) \ or state.world_view.game_state == "kick_in_{0}".format(state.world_view.side) \ or state.world_view.game_state == "goal_kick_{0}".format(state.world_view.side) \ or state.world_view.game_state == "offside_{0}".format(opponent_side): debug_msg( str(state.now()) + " | free_kick, corner_kick, kick_in, kick_off, goal_kick, offside -> go to ball or position optimally", "GOALIE") if _ball_unknown(state): return _locate_ball_objective(state) if state.is_near_ball(KICKABLE_MARGIN): if state.world_view.sim_time - state.action_history.last_look_for_pass_targets > 2: return Objective(state, lambda: actions.look_for_pass_target(state), lambda: True, 2) if _choose_pass_target(state, must_pass=True) is not None: return Objective( state, lambda: actions.pass_to_player( state, _choose_pass_target(state, must_pass=True)), lambda: True, 1) else: return Objective(state, lambda: actions.look_for_pass_target(state), lambda: True, 2) elif state.is_nearest_ball(1): return _jog_to_ball_objective(state) else: return _position_optimally_objective_goalie(state) ball: Ball = state.world_view.ball.get_value() # If in possession of the ball -> Pass to team mate if state.is_near_ball(KICKABLE_MARGIN): pass_target = _choose_pass_target(state) if pass_target is not None: debug_msg( str(state.now()) + " | in possession, pass target found -> pass to teammate", "GOALIE") return Objective( state, lambda: actions.pass_to_player( state, _choose_pass_target(state)), lambda: True, 1) # No suitable pass target debug_msg( str(state.now()) + " | in possession, pass target not found -> look for pass target", "GOALIE") return Objective(state, lambda: actions.look_for_pass_target(state), lambda: True, 1) # If ball coming to goalie inside box -> Catch ball positions = ball.project_ball_position(2, 0) if positions is not None and state.is_inside_own_box(): debug_msg( str(state.now()) + " | Ball incoming inside box -> Catch ball", "GOALIE") ball_pos_1_tick: Coordinate = positions[0] if ball_pos_1_tick.euclidean_distance_from( state.position.get_value()) < CATCHABLE_MARGIN: return Objective( state, lambda: actions.catch_ball(state, ball_pos_1_tick), lambda: True, 1) # If ball coming towards us or ball will hit goal soon -> Intercept if (ball.will_hit_goal_within(ticks=5) or (state.is_nearest_ball(1) and state.is_ball_inside_own_box())): debug_msg( str(state.now()) + " | ball coming towards us or ball will hit goal soon -> run to ball and catch!", "GOALIE") intercept_actions = actions.intercept_2(state, "catch") if intercept_actions is not None: return Objective(state, lambda: intercept_actions) else: return _rush_to_ball_objective(state) # If position not alligned with ball y-position -> Adjust y-position if state.position.is_value_known( ) and state.world_view.ball.is_value_known( ) and not configurations.USING_PASS_CHAIN_STRAT: debug_msg( str(state.now()) + " | Position not optimal -> adjust position", "GOALIE") return _position_optimally_objective_goalie(state) # If nothing to do -> Face ball debug_msg(str(state.now()) + " | Nothing to do -> Face ball", "GOALIE") return Objective(state, lambda: actions.face_ball(state), lambda: True, 1)
def _find_applicable_strat_player(state: PlayerState) -> _StrategyGenerator: # Matches the current state of the game to a uppaal model, if applicable # Check if dribble strategy model can be applied if state.team_name in DRIBBLE_OR_PASS_TEAMS and state.needs_dribble_or_pass_strat( ): print(state.now(), " DRIBBLE STRAT - Player : ", state.num) possession_dir = Path(__file__).parent / "models" / "possessionmodel" if not possession_dir.exists(): os.makedirs(possession_dir) original_pos_model = Path( possession_dir).parent / "PassOrDribbleModel.xml" model_name = "possessionmodel{0}{1}.xml".format( state.world_view.side, state.num) new_pos_file = possession_dir / model_name if not new_pos_file.exists(): f = open(new_pos_file, "x") copyfile(original_pos_model, new_pos_file) f.close() return _StrategyGenerator( "/possessionmodel/possessionmodel{0}{1}".format( state.world_view.side, state.num), _update_dribble_or_pass_model, _extract_pass_or_dribble_strategy) # Check if stamina strategy model can be applied if state.team_name in STAMINA_MODEL_TEAMS and ( state.now() % 121) == (state.num + 1) * 10: print(state.num, state.team_name) return _StrategyGenerator( "/staminamodel/staminamodel{0}{1}".format(state.world_view.side, state.num), _update_stamina_model_simple, _extract_stamina_solution_simple) # Check if the goalie defence model can be applied if state.team_name in GOALIE_MODEL_TEAMS and state.player_type == "goalie": ball_possessor = state.get_ball_possessor() if ball_possessor is not None and ball_possessor.coord is not None: side = 1 if state.world_view.side == "r" else -1 steps_per_meter = goalie_strategy.STEPS_PER_METER # Convert coordinate to fit the squares from the strategy possessor_new_x = math.floor(ball_possessor.coord.pos_x * side / steps_per_meter) * steps_per_meter possessor_new_y = math.floor( ball_possessor.coord.pos_y / steps_per_meter) * steps_per_meter goalie_new_x = math.floor(state.position.get_value().pos_x * side / steps_per_meter) * steps_per_meter goalie_new_y = math.floor(state.position.get_value().pos_y / steps_per_meter) * steps_per_meter if abs(state.position.get_value().pos_x) > 52.5: goalie_new_x = 52 * side # Example: "(36.5, -19.5),(47.5, -8.5)" -> "(goalie_x, goalie_y),(player_x, player_y)" key = "({0}.0, {1}.0),({2}.0, {3}.0)".format( str(goalie_new_x), str(goalie_new_y), str(possessor_new_x), str(possessor_new_y)) if key in state.goalie_position_dict.keys(): result = state.goalie_position_dict[key] optimal_x = int(goalie_new_x * side + result[0] * side) optimal_y = int(goalie_new_y + result[1]) optimal_coord = Coordinate(optimal_x, optimal_y) state.goalie_position_strategy = optimal_coord return None
def _update_dribble_or_pass_model(state: PlayerState, model: UppaalModel): # This function edits the UPPAAL file to represent the current state of the game # Amount of ticks to forecast game state # This should be the expected time that it takes to generate the strategy FORECAST_TICKS = 6 team_mates = state.world_view.get_teammates_precarious(state.team_name, 10, min_dist=5) opponents = state.world_view.get_opponents_precarious(state.team_name, 10, min_dist=0) # Forecast position of the ball possessor if state.get_y_north_velocity_vector() is not None: possessor_forecasted = ( state.position.get_value().vector() + state.get_y_north_velocity_vector() * FORECAST_TICKS).coord() else: possessor_forecasted = state.position.get_value() # Forecast position of other players forecasted_team_positions = list( map( lambda p: p.get_value().forecasted_position( (state.now() - p.last_updated_time) + FORECAST_TICKS), team_mates)) forecasted_opponent_positions = list( map( lambda p: p.get_value().forecasted_position( (state.now() - p.last_updated_time) + FORECAST_TICKS), opponents)) if state.players_close_behind > 0: forecasted_opponent_positions.append( Coordinate( possessor_forecasted.pos_x - 1, possessor_forecasted.pos_y, )) # Convert to textual format understandable by uppaal team_pos_value = _to_3d_double_array_coordinate(forecasted_team_positions) opponent_pos_value = _to_3d_double_array_coordinate( forecasted_opponent_positions) possessor_val = _to_2d_double_array_coordinate(possessor_forecasted) model.set_global_declaration_value("TEAM_MATES", len(forecasted_team_positions)) model.set_global_declaration_value("OPPONENTS", len(forecasted_opponent_positions)) model.set_global_declaration_value("team_pos[TEAM_MATES][2]", team_pos_value) model.set_global_declaration_value("opponent_pos[OPPONENTS][2]", opponent_pos_value) model.set_global_declaration_value("possessor[2]", possessor_val) if state.is_test_player(): # Debugging all_posis = list( map(lambda p: p.get_value().coord, state.world_view.other_players)) debug_msg( str(state.now()) + " All positions: " + str(all_posis), "DRIBBLE_PASS_MODEL") debug_msg( str(state.now()) + " Forecasted team positions: " + str(team_pos_value), "DRIBBLE_PASS_MODEL") debug_msg( str(state.now()) + " Forecasted opponent positions: " + str(opponent_pos_value), "DRIBBLE_PASS_MODEL") debug_msg( str(state.now()) + " Forecasted possessor position: " + str(possessor_val), "DRIBBLE_PASS_MODEL") return forecasted_team_positions