def place_ball(self, game): """ Place the ball when kicking. """ left_center = Square(7, 8) right_center = Square(20, 8) if game.is_team_side(left_center, self.opp_team): return Action(ActionType.PLACE_BALL, position=left_center) return Action(ActionType.PLACE_BALL, position=right_center)
def setup(self, game): """ Move players from the reserves to the pitch """ i = len(game.get_players_on_pitch(self.my_team)) reserves = game.get_reserves(self.my_team) if i == 11 or len(reserves) == 0: return Action(ActionType.END_SETUP) player = reserves[0] y = 3 x = 13 if game.is_team_side(Square(13, 3), self.my_team) else 14 return Action(ActionType.PLACE_PLAYER, player=player, position=Square(x, y + i))
def _make_plan(self, game, ball_carrier): #print("1. Stand up marked players") for player in self.my_team.players: if player.position is not None and not player.state.up and not player.state.stunned and not player.state.used: if game.num_tackle_zones_in(player) > 0: self.actions.append(Action(ActionType.START_MOVE, player=player)) self.actions.append(Action(ActionType.STAND_UP)) #print(f"Stand up marked player {player.role.name}") return #print("2. Move ball carrier to endzone") if ball_carrier is not None and ball_carrier.team == self.my_team and not ball_carrier.state.used: #print("2.1 Can ball carrier score with high probability") td_path = pf.get_safest_path_to_endzone(game, ball_carrier, allow_team_reroll=True) if td_path is not None and td_path.prob >= 0.7: self.actions.append(Action(ActionType.START_MOVE, player=ball_carrier)) self.actions.append(Action(ActionType.MOVE, position=td_path.steps[-1])) #print(f"Score with ball carrier, p={td_path.prob}") return #print("2.2 Hand-off action to scoring player") if game.is_handoff_available(): # Get players in scoring range unused_teammates = [] for player in self.my_team.players: if player.position is not None and player != ball_carrier and not player.state.used and player.state.up: unused_teammates.append(player) # Find other players in scoring range handoff_p = None handoff_path = None for player in unused_teammates: if game.get_distance_to_endzone(player) > player.num_moves_left(): continue td_path = pf.get_safest_path_to_endzone(game, player, allow_team_reroll=True) if td_path is None: continue handoff_path = pf.get_safest_path(game, ball_carrier, player.position, allow_team_reroll=True) if handoff_path is None: continue p_catch = game.get_catch_prob(player, handoff=True, allow_catch_reroll=True, allow_team_reroll=True) p = td_path.prob * handoff_path.prob * p_catch if handoff_p is None or p > handoff_p: handoff_p = p handoff_path = handoff_path # Hand-off if high probability or last turn if handoff_path is not None and (handoff_p >= 0.7 or self.my_team.state.turn == 8): self.actions = [Action(ActionType.START_HANDOFF, player=ball_carrier), Action(ActionType.MOVE, handoff_path.steps[-1])] return #print("2.3 Move safely towards the endzone") if game.num_tackle_zones_in(ball_carrier) == 0: paths = pf.get_all_paths(game, ball_carrier) best_path = None best_distance = 100 target_x = game.get_opp_endzone_x(self.my_team) for path in paths: distance_to_endzone = abs(target_x - path.steps[-1].x) if path.prob == 1 and (best_path is None or distance_to_endzone < best_distance): best_path = path best_distance = distance_to_endzone if best_path is not None: steps = [] for step in best_path.steps: if game.num_tackle_zones_at(ball_carrier, step) > 0: break if len(steps) >= ball_carrier.num_moves_left(): break steps.append(step) if len(steps) > 0: self.actions.append(Action(ActionType.START_MOVE, player=ball_carrier)) for step in steps: self.actions.append(Action(ActionType.MOVE, position=step)) #print(f"Move ball carrier {ball_carrier.role.name}") return #print("3. Safe blocks") attacker, defender, p_self_up, p_opp_down, block_p_fumble_self, block_p_fumble_opp = self._get_safest_block(game) if attacker is not None and p_self_up > 0.94 and block_p_fumble_self == 0: self.actions.append(Action(ActionType.START_BLOCK, player=attacker)) self.actions.append(Action(ActionType.BLOCK, position=defender.position)) #print(f"Safe block with {attacker.role.name} -> {defender.role.name}, p_self_up={p_self_up}, p_opp_down={p_opp_down}") return #print("4. Pickup ball") if game.get_ball_carrier() is None: pickup_p = None pickup_player = None pickup_path = None for player in self.my_team.players: if player.position is not None and not player.state.used: if player.position.distance(game.get_ball_position()) <= player.get_ma() + 2: path = pf.get_safest_path(game, player, game.get_ball_position()) if path is not None: p = path.prob if pickup_p is None or p > pickup_p: pickup_p = p pickup_player = player pickup_path = path if pickup_player is not None and pickup_p > 0.33: self.actions.append(Action(ActionType.START_MOVE, player=pickup_player)) if not pickup_player.state.up: self.actions.append(Action(ActionType.STAND_UP)) for step in pickup_path.steps: self.actions.append(Action(ActionType.MOVE, position=step)) #print(f"Pick up the ball with {pickup_player.role.name}, p={pickup_p}") # Find safest path towards endzone if game.num_tackle_zones_at(pickup_player, game.get_ball_position()) == 0: paths = pf.get_all_paths(game, pickup_player, from_position=game.get_ball_position(), num_moves_used=len(pickup_path)) best_path = None best_distance = 100 target_x = game.get_opp_endzone_x(self.my_team) for path in paths: distance_to_endzone = abs(target_x - path.steps[-1].x) if path.prob == 1 and (best_path is None or distance_to_endzone < best_distance): best_path = path best_distance = distance_to_endzone if best_path is not None: steps = [] for step in best_path.steps: if game.num_tackle_zones_at(pickup_player, step) > 0: break if len(steps) + len(pickup_path.steps) >= pickup_player.get_ma(): break steps.append(step) if len(steps) > 0: self.actions.append(Action(ActionType.START_MOVE, player=ball_carrier)) for step in steps: self.actions.append(Action(ActionType.MOVE, position=step)) #print(f"- Move ball carrier {pickup_player.role.name}") return # Scan for unused players that are not marked open_players = [] for player in self.my_team.players: if player.position is not None and not player.state.used and game.num_tackle_zones_in(player) == 0: open_players.append(player) #print("5. Move receivers into scoring distance if not already") for player in open_players: if player.has_skill(Skill.CATCH) and player != ball_carrier: if game.get_distance_to_endzone(player) > player.num_moves_left(): continue paths = pf.get_all_paths(game, ball_carrier) best_path = None best_distance = 100 target_x = game.get_opp_endzone_x(self.my_team) for path in paths: distance_to_endzone = abs(target_x - path.steps[-1].x) if path.prob == 1 and (best_path is None or distance_to_endzone < best_distance): best_path = path best_distance = distance_to_endzone if best_path is not None: steps = [] for step in best_path.steps: if len(steps) >= player.get_ma() + (3 if not player.state.up else 0): break if game.num_tackle_zones_at(player, step) > 0: break if step.distance(best_path.steps[-1]) < player.get_ma(): break steps.append(step) if len(steps) > 0: self.actions.append(Action(ActionType.START_MOVE, player=player)) if not player.state.up: self.actions.append(Action(ActionType.STAND_UP)) for step in steps: self.actions.append(Action(ActionType.MOVE, position=step)) print(f"Move receiver {player.role.name}") return #print("6. Blitz with open block players") if game.is_blitz_available(): best_blitz_attacker = None best_blitz_defender = None best_blitz_score = None best_blitz_path = None for blitzer in open_players: if blitzer.position is not None and not blitzer.state.used and blitzer.has_skill(Skill.BLOCK): blitz_paths = pf.get_all_paths(game, blitzer, blitz=True) for path in blitz_paths: final_position = path.steps[-2] if len(path.steps) > 1 else blitzer.position for defender in game.get_adjacent_players(final_position, team=game.get_opp_team(blitzer.team)): p_self, p_opp, p_fumble_self, p_fumble_opp = game.get_blitz_probs(blitzer, final_position, defender) p_self_up = path.prob * (1-p_self) p_opp = path.prob * p_opp p_fumble_opp = p_fumble_opp * path.prob if blitzer == game.get_ball_carrier(): p_fumble_self = path.prob + (1 - path.prob) * p_fumble_self score = p_self_up + p_opp + p_fumble_opp - p_fumble_self if best_blitz_score is None or score > best_blitz_score: best_blitz_attacker = blitzer best_blitz_defender = defender best_blitz_score = score best_blitz_path = path if best_blitz_attacker is not None and best_blitz_score >= 1.25: self.actions.append(Action(ActionType.START_BLITZ, player=best_blitz_attacker)) self.actions.append(Action(ActionType.MOVE, position=best_blitz_path.steps[-1])) #print(f"Blitz with {best_blitz_attacker.role.name}, score={best_blitz_score}") return #print("7. Make cage around ball carrier") cage_positions = [ Square(game.get_ball_position().x - 1, game.get_ball_position().y - 1), Square(game.get_ball_position().x + 1, game.get_ball_position().y - 1), Square(game.get_ball_position().x - 1, game.get_ball_position().y + 1), Square(game.get_ball_position().x + 1, game.get_ball_position().y + 1) ] if ball_carrier is not None: for cage_position in cage_positions: if game.get_player_at(cage_position) is None and not game.is_out_of_bounds(cage_position): for player in open_players: if player == ball_carrier or player.position in cage_positions: continue if player.position.distance(cage_position) > player.num_moves_left(): continue if game.num_tackle_zones_in(player) > 0: continue path = pf.get_safest_path(game, player, cage_position) if path is not None and path.prob > 0.94: self.actions.append(Action(ActionType.START_MOVE, player=player)) self.actions.append(Action(ActionType.MOVE, position=path.steps[-1])) #print(f"Make cage around towards ball carrier {player.role.name}") return # Scan for assist positions assist_positions = [] for player in game.get_opp_team(self.my_team).players: if player.position is None or not player.state.up: continue opponents = game.get_adjacent_opponents(player, down=False) for opponent in opponents: att_str, def_str = game.get_block_strengths(player, opponent) if def_str >= att_str: for open_position in game.get_adjacent_squares(player.position, occupied=False): if len(game.get_adjacent_players(open_position, team=self.opp_team, down=False)) == 1: assist_positions.append(open_position) #print("8. Move non-marked players to assist") for player in open_players: paths = pf.get_all_paths(game, player) for assist_position in assist_positions: assist_path = None for path in paths: if path.steps[-1] == assist_position: if path.prob == 1: self.actions.append(Action(ActionType.START_MOVE, player=player)) self.actions.append(Action(ActionType.MOVE, position=path.steps[-1])) #print(f"Move assister {player.role.name} to {assist_position.to_json}") return #print("9. Move towards the ball") for player in open_players: if player == ball_carrier: continue if game.num_tackle_zones_in(player) > 0: continue if ball_carrier is None: paths = pf.get_all_paths(game, player) shortest_distance = None path = None for p in paths: distance = p.steps[-1].distance(game.get_ball_position()) if shortest_distance is None or (p.prob == 1 and distance < shortest_distance): shortest_distance = distance path = p elif ball_carrier.team != self.my_team: paths = pf.get_all_paths(game, player) shortest_distance = None path = None for p in paths: distance = p.steps[-1].distance(ball_carrier.position) if shortest_distance is None or (p.prob == 1 and distance < shortest_distance): shortest_distance = distance path = p else: continue if path is not None: if len(path.steps) > 0: self.actions.append(Action(ActionType.START_MOVE, player=player)) self.actions.append(Action(ActionType.MOVE, position=path.steps[-1])) #print(f"Move towards ball {player.role.name}") return #print("10. Risky blocks") attacker, defender, p_self_up, p_opp_down, block_p_fumble_self, block_p_fumble_opp = self._get_safest_block(game) if attacker is not None and (p_opp_down > (1-p_self_up) or block_p_fumble_opp > 0): self.actions.append(Action(ActionType.START_BLOCK, player=attacker)) self.actions.append(Action(ActionType.BLOCK, position=defender.position)) #print(f"Block with {player.role.name} -> {defender.role.name}, p_self_up={p_self_up}, p_opp_down={p_opp_down}") return #print("11. End turn") self.actions.append(Action(ActionType.END_TURN))