예제 #1
0
def test_out_of_bounds():
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(1, 1)
    game.put(player, position)
    for neighbor in game.get_adjacent_squares(position):
        if game.is_out_of_bounds(neighbor):
            path = pf.get_safest_path(game, player, neighbor)
            assert path is None
예제 #2
0
def test_neighbors():
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(5, 5)
    game.put(player, position)
    for neighbor in game.get_adjacent_squares(position):
        path = pf.get_safest_path(game, player, neighbor)
        assert len(path) == 1 and path.steps[0] == neighbor
        assert path.prob == 1.0
예제 #3
0
def test_gfi():
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(5, 5)
    game.put(player, position)
    for gfis in [0, 1, 2]:
        moves = player.get_ma() + gfis
        target = Square(position.x + moves, position.y)
        path = pf.get_safest_path(game, player, target)
        assert len(path.steps) == moves and path.steps[-1] == target
        assert path.prob == (5 / 6)**gfis
예제 #4
0
def test_avoid_path():
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(1, 8)
    game.put(player, position)
    opp = game.get_reserves(game.state.away_team)[0]
    opp_position = Square(3, 8)
    game.put(opp, opp_position)
    target_a = Square(6, 8)
    path = pf.get_safest_path(game, player, target_a)
    assert path is not None
    assert len(path.steps) == 6
    assert path.prob == 1.0
예제 #5
0
def test_dodge_needed_path_long():
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(1, 8)
    game.put(player, position)
    opp = game.get_reserves(game.state.away_team)[0]
    opp_position = Square(3, 8)
    game.put(opp, opp_position)
    target_a = Square(9, 8)
    path = pf.get_safest_path(game, player, position=target_a)
    assert path is not None
    assert len(path.steps) == 8
    assert path.prob == (4 / 6) * (5 / 6) * (5 / 6)
예제 #6
0
def test_all_paths(skills_and_rerolls):
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    position = Square(1, 1)
    game.put(player, position)
    skill, reroll = skills_and_rerolls
    if skill:
        player.extra_skills = [Skill.SURE_FEET]
    for y in range(game.arena.height):
        for x in range(game.arena.width):
            square = Square(x, y)
            if position != square and not game.is_out_of_bounds(square):
                if position.distance(square) != player.get_ma() + 2:
                    continue
                    # TODO: REMOVE
                path = pf.get_safest_path(game,
                                          player,
                                          square,
                                          allow_team_reroll=reroll)
                if position.distance(square) > player.get_ma() + 2:
                    assert path is None
                else:
                    p = 5 / 6
                    if position.distance(square) == player.get_ma() + 2:
                        p_clean = p * p
                        p_reroll_one = (p * (1 - p) * p)
                        p_reroll_both = (1 - p) * p * (1 - p) * p
                        if reroll and not skill or not reroll and skill:
                            p = p_clean + p_reroll_one * 2
                        elif reroll and skill:
                            p = p_clean + p_reroll_one * 2 + p_reroll_both
                        else:
                            p = p_clean
                        assert path is not None
                        assert path.prob == pytest.approx(p, PROP_PRECISION)
                    elif position.distance(square) == player.get_ma() + 1:
                        assert path is not None
                        if reroll or skill:
                            p = p + (1 - p) * p
                        assert path.prob == pytest.approx(p, PROP_PRECISION)
                    else:
                        assert path is not None
                        p = 1.0
                        assert path.prob == p
예제 #7
0
def test_sure_feet_over_ag4_dodge(sure_feet):
    game = get_game_turn(empty=True)
    player = game.get_reserves(game.state.home_team)[0]
    player.role.ma = 4
    player.role.ag = 4
    if sure_feet:
        player.extra_skills = [Skill.SURE_FEET]
    game.put(player, Square(4, 1))
    opp1 = game.get_reserves(game.state.away_team)[0]
    game.put(opp1, Square(3, 3))
    opp2 = game.get_reserves(game.state.away_team)[1]
    game.put(opp2, Square(5, 3))
    target = Square(2, 4)
    path = pf.get_safest_path(game, player, target)
    assert path is not None
    if sure_feet:
        assert len(path.steps) == 5
        p = (5 / 6)
        assert path.prob == p + (1 - p) * p
    else:
        assert len(path.steps) == 4
        p = (5 / 6)
        assert path.prob == p
예제 #8
0
    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))