Beispiel #1
0
def scripted_action(game: botbowl.Game) -> Optional[Action]:
    available_action_types = {
        action_choice.action_type
        for action_choice in game.get_available_actions()
    }

    for at in use_directly_action_types:
        if at in available_action_types:
            return Action(at)

    if ActionType.PLACE_BALL in available_action_types:
        x = game.arena.width // 4
        if game.active_team is game.state.away_team:
            x *= 3
        y = game.arena.height // 2
        return Action(ActionType.PLACE_BALL, position=botbowl.Square(x, y))

    proc = game.get_procedure()
    if type(proc) is Setup:
        if game.is_setup_legal(game.active_team):
            return Action(ActionType.END_SETUP)
        for at in available_action_types:
            if at not in {ActionType.END_SETUP, ActionType.PLACE_PLAYER}:
                return Action(at)

    return None
Beispiel #2
0
 def reroll(self, game):
     """
     Select between USE_REROLL and DONT_USE_REROLL
     """
     reroll_proc = game.get_procedure()
     context = reroll_proc.context
     if type(context) == botbowl.Dodge:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.Pickup:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.PassAttempt:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.Catch:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.GFI:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.BloodLust:
         return Action(ActionType.USE_REROLL)
     if type(context) == botbowl.Block:
         attacker = context.attacker
         attackers_down = 0
         for die in context.roll.dice:
             if die.get_value() == BBDieResult.ATTACKER_DOWN:
                 attackers_down += 1
             elif die.get_value(
             ) == BBDieResult.BOTH_DOWN and not attacker.has_skill(
                     Skill.BLOCK) and not attacker.has_skill(Skill.WRESTLE):
                 attackers_down += 1
         if attackers_down > 0 and context.favor != self.my_team:
             return Action(ActionType.USE_REROLL)
         if attackers_down == len(
                 context.roll.dice) and context.favor != self.opp_team:
             return Action(ActionType.USE_REROLL)
         return Action(ActionType.DONT_USE_REROLL)
     return Action(ActionType.DONT_USE_REROLL)
Beispiel #3
0
def test_expand_move(data):
    move_target, outcome_probs = data
    assert sum(outcome_probs) == 1.0
    game, (player, _, _) = get_custom_game_turn(player_positions=[(1, 1)],
                                                opp_player_positions=[(1, 3),
                                                                      (3, 1)],
                                                forward_model_enabled=True,
                                                pathfinding_enabled=True)

    game.step(Action(ActionType.START_MOVE, position=player.position))

    action = Action(ActionType.MOVE, position=move_target)
    parent_action_node: ActionNode = ActionNode(game, parent=None)
    next_node: Node = expand_action(game, action, parent_action_node)

    assert next_node.parent is parent_action_node

    if len(outcome_probs) == 1:
        assert type(next_node) is ActionNode
    else:
        next_node: ChanceNode
        assert type(next_node) is ChanceNode
        assert sum(next_node.child_probability) == 1.0
        assert all(y == approx(x, abs=1e-12) for x, y in zip(
            sorted(next_node.child_probability), sorted(outcome_probs)))
Beispiel #4
0
def test_expand_block():
    game, (attacker, _,
           defender) = get_custom_game_turn(player_positions=[(5, 5), (7, 7)],
                                            opp_player_positions=[(6, 6)],
                                            forward_model_enabled=True)
    defender.extra_skills.append(Skill.DODGE)
    tree = SearchTree(game)

    next_node, = tree.expand_action_node(
        tree.root_node, Action(ActionType.START_BLOCK, player=attacker))

    assert len(tree.all_action_nodes) == 2
    next_node, *_ = tree.expand_action_node(
        next_node, Action(ActionType.BLOCK, position=defender.position))

    assert len(tree.all_action_nodes) == 6
    next_node, = tree.expand_action_node(
        next_node, Action(ActionType.SELECT_DEFENDER_DOWN))

    assert len(tree.all_action_nodes) == 7
    next_node, = tree.expand_action_node(
        next_node, Action(ActionType.PUSH, position=Square(7, 6)))

    assert len(tree.all_action_nodes) == 8
    next_node, *_ = tree.expand_action_node(
        next_node, Action(ActionType.FOLLOW_UP, position=Square(6, 6)))

    assert len(tree.all_action_nodes) == 11
Beispiel #5
0
def path_to_move_actions(game: botbowl.Game,
                         player: botbowl.Player,
                         path: Path,
                         do_assertions=True) -> List[Action]:
    """
    This function converts a path into a list of actions corresponding to that path.
    If you provide a handoff, foul or blitz path, then you have to manally set action type.
    :param game:
    :param player: player to move
    :param path: a path as returned by the pathfinding algorithms
    :param do_assertions: if False, it turns off the validation, can be helpful when the GameState will change before
                          this path is executed.
    :returns: List of actions corresponding to 'path'.
    """

    if path.block_dice is not None:
        action_type = ActionType.BLOCK
    elif path.handoff_roll is not None:
        action_type = ActionType.HANDOFF
    elif path.foul_roll is not None:
        action_type = ActionType.FOUL
    else:
        action_type = ActionType.MOVE

    active_team = game.state.available_actions[0].team
    player_at_target = game.get_player_at(path.get_last_step())

    if do_assertions:
        if action_type is ActionType.MOVE:
            assert player_at_target is None or player_at_target is game.get_active_player(
            )
        elif action_type is ActionType.BLOCK:
            assert game.get_opp_team(active_team) is player_at_target.team
            assert player_at_target.state.up
        elif action_type is ActionType.FOUL:
            assert game.get_opp_team(active_team) is player_at_target.team
            assert not player_at_target.state.up
        elif action_type is ActionType.HANDOFF:
            assert active_team is player_at_target.team
            assert player_at_target.state.up
        else:
            raise Exception(f"Unregonized action type {action_type}")

    final_action = Action(action_type, position=path.get_last_step())

    if game._is_action_allowed(final_action):
        return [final_action]
    else:
        actions = []
        if not player.state.up and path.steps[0] == player.position:
            actions.append(Action(ActionType.STAND_UP, player=player))
            actions.extend(
                Action(ActionType.MOVE, position=sq)
                for sq in path.steps[1:-1])
        else:
            actions.extend(
                Action(ActionType.MOVE, position=sq) for sq in path.steps[:-1])
        actions.append(final_action)
        return actions
Beispiel #6
0
 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)
Beispiel #7
0
 def interception(self, game):
     """
     Select interceptor.
     """
     for action in game.state.available_actions:
         if action.action_type == ActionType.SELECT_PLAYER:
             for player, rolls in zip(action.players, action.rolls):
                 return Action(ActionType.SELECT_PLAYER, player=player)
     return Action(ActionType.SELECT_NONE)
Beispiel #8
0
    def block(self, game):
        """
        Select block die or reroll.
        """
        # Get attacker and defender
        attacker = game.get_procedure().attacker
        defender = game.get_procedure().defender
        is_blitz = game.get_procedure().blitz
        dice = game.num_block_dice(attacker, defender, blitz=is_blitz)

        # Loop through available dice results
        actions = set()
        for action_choice in game.state.available_actions:
            actions.add(action_choice.action_type)

        # 1. DEFENDER DOWN
        if ActionType.SELECT_DEFENDER_DOWN in actions:
            return Action(ActionType.SELECT_DEFENDER_DOWN)

        if ActionType.SELECT_DEFENDER_STUMBLES in actions and not (
                defender.has_skill(Skill.DODGE)
                and not attacker.has_skill(Skill.TACKLE)):
            return Action(ActionType.SELECT_DEFENDER_STUMBLES)

        if ActionType.SELECT_BOTH_DOWN in actions and not defender.has_skill(
                Skill.BLOCK) and attacker.has_skill(Skill.BLOCK):
            return Action(ActionType.SELECT_BOTH_DOWN)

        # 2. BOTH DOWN if opponent carries the ball and doesn't have block
        if ActionType.SELECT_BOTH_DOWN in actions and game.get_ball_carrier(
        ) == defender and not defender.has_skill(Skill.BLOCK):
            return Action(ActionType.SELECT_BOTH_DOWN)

        # 3. USE REROLL if defender carries the ball
        if ActionType.USE_REROLL in actions and game.get_ball_carrier(
        ) == defender:
            return Action(ActionType.USE_REROLL)

        # 4. PUSH
        if ActionType.SELECT_DEFENDER_STUMBLES in actions:
            return Action(ActionType.SELECT_DEFENDER_STUMBLES)

        if ActionType.SELECT_PUSH in actions:
            return Action(ActionType.SELECT_PUSH)

        # 5. BOTH DOWN
        if ActionType.SELECT_BOTH_DOWN in actions:
            return Action(ActionType.SELECT_BOTH_DOWN)

        # 6. USE REROLL to avoid attacker down unless a one-die block
        if ActionType.USE_REROLL in actions and dice > 1:
            return Action(ActionType.USE_REROLL)

        # 7. ATTACKER DOWN
        if ActionType.SELECT_ATTACKER_DOWN in actions:
            return Action(ActionType.SELECT_ATTACKER_DOWN)
Beispiel #9
0
def convert_to_actions(
        action_choice: botbowl.ActionChoice) -> Iterable[Action]:
    if len(action_choice.positions) > 0:
        return (Action(action_choice.action_type, position=sq)
                for sq in action_choice.positions)
    elif len(action_choice.players) > 0:
        return (Action(action_choice.action_type, player=p)
                for p in action_choice.players)
    else:
        return (Action(action_choice.action_type) for _ in range(1))
Beispiel #10
0
 def touchback(self, game):
     """
     Select player to give the ball to.
     """
     p = None
     for player in game.get_players_on_pitch(self.my_team, up=True):
         if Skill.BLOCK in player.get_skills():
             return Action(ActionType.SELECT_PLAYER, player=player)
         p = player
     return Action(ActionType.SELECT_PLAYER, player=p)
Beispiel #11
0
 def high_kick(self, game):
     """
     Select player to move under the ball.
     """
     ball_pos = game.get_ball_position()
     if game.is_team_side(game.get_ball_position(), self.my_team) and \
             game.get_player_at(game.get_ball_position()) is None:
         for player in game.get_players_on_pitch(self.my_team, up=True):
             if Skill.BLOCK in player.get_skills(
             ) and game.num_tackle_zones_in(player) == 0:
                 return Action(ActionType.SELECT_PLAYER,
                               player=player,
                               position=ball_pos)
     return Action(ActionType.SELECT_NONE)
Beispiel #12
0
    def __call__(
            self, game: botbowl.Game
    ) -> Tuple[float, np.ndarray, List[botbowl.Action]]:
        action = scripted_action(game)
        if action is not None:
            return 0.0, np.array([1.0]), [action]

        actions: MockPolicy.ActionProbList = []

        if self.end_setup:
            self.end_setup = False
            return 0.0, np.array([1.0]), [Action(ActionType.END_SETUP)]

        for action_choice in game.get_available_actions():
            action_type = action_choice.action_type

            if action_type in self.convert_function:
                actions.extend(self.convert_function[action_type](
                    game, action_choice))

            elif action_type in self.positional_types:
                if len(action_choice.positions) > 0:
                    positions = action_choice.positions
                else:
                    positions = [p.position for p in action_choice.players]

                for pos in positions:
                    actions.append((Action(action_type, position=pos), 1))

            elif action_choice.action_type in self.simple_types:
                actions.append((Action(action_type), 1))

            elif type(game.get_procedure()) is Setup and action_type not in {
                    ActionType.END_SETUP, ActionType.PLACE_PLAYER
            }:
                actions.append((Action(action_type), 1))
                self.end_setup = True

        if len(actions) == 0 and ActionType.END_PLAYER_TURN in [
                ac.action_type for ac in game.state.available_actions
        ]:
            actions.append((Action(ActionType.END_PLAYER_TURN), 1))

        action_objects, probabilities = zip(*actions)
        probabilities = np.array(probabilities, dtype=np.float)
        probabilities += 0.0001 * np.random.random(len(probabilities))
        probabilities /= sum(probabilities)

        return 0.0, probabilities, action_objects
Beispiel #13
0
    def __init__(self, game: botbowl.Game):
        self.actions = []
        self.priority_actions = []

        for action_choice in game.get_available_actions():
            if action_choice.action_type not in {
                    ActionType.START_MOVE, ActionType.MOVE,
                    ActionType.END_PLAYER_TURN
            }:
                continue

            if action_choice.action_type == ActionType.MOVE:
                prio_move_square = get_priority_move_square(
                    action_choice, game)

                if prio_move_square is not None:
                    self.priority_actions.append(
                        Action(action_choice.action_type,
                               position=prio_move_square))

            self.actions.extend(convert_to_actions(action_choice))

        if len(self.actions) == 0:
            self.actions.extend(
                collapse(
                    convert_to_actions(action_choice)
                    for action_choice in game.get_available_actions()))

        assert len(self.actions) > 0
        shuffle(self.actions)
Beispiel #14
0
 def push(self, game):
     """
     Select square to push to.
     """
     # Loop through available squares
     for position in game.state.available_actions[0].positions:
         return Action(ActionType.PUSH, position=position)
Beispiel #15
0
 def start_handoff_actions(self, game: botbowl.Game,
                           action_choice) -> ActionProbList:
     ball = game.get_ball()
     if ball is not None and ball.is_carried:
         if ball.position in action_choice.positions:
             return [(Action(ActionType.START_HANDOFF,
                             position=[ball.position]), 1)]
     return []
Beispiel #16
0
 def follow_up(self, game):
     """
     Follow up or not. ActionType.FOLLOW_UP must be used together with a position.
     """
     player = game.state.active_player
     for position in game.state.available_actions[0].positions:
         # Always follow up
         if player.position != position:
             return Action(ActionType.FOLLOW_UP, position=position)
Beispiel #17
0
def test_expand_throw_in():
    game, (attacker,
           defender) = get_custom_game_turn(player_positions=[(5, 2)],
                                            opp_player_positions=[(5, 1)],
                                            ball_position=(5, 1),
                                            forward_model_enabled=True,
                                            pathfinding_enabled=True)

    with only_fixed_rolls(game, block_dice=[BBDieResult.DEFENDER_DOWN]):
        game.step(Action(ActionType.START_BLOCK, position=attacker.position))
        game.step(Action(ActionType.BLOCK, position=defender.position))
        game.step(Action(ActionType.SELECT_DEFENDER_DOWN))

    action = Action(ActionType.PUSH, position=Square(5, 0))

    tree = SearchTree(game)
    tree.expand_action_node(tree.root_node, action)
    assert len(tree.all_action_nodes) == 2
Beispiel #18
0
    def move_actions(self, game: botbowl.Game,
                     action_choice) -> ActionProbList:
        if game.get_player_action_type(
        ) in self.player_actiontypes_without_move_actions:
            return []

        action_probs = []

        player = game.get_active_player()
        ball_carrier = game.get_ball_carrier()
        is_ball_carrier = player is game.get_ball_carrier()

        if player.state.moves > 0 and not is_ball_carrier:
            return []
        elif is_ball_carrier and player.state.moves > 0:
            action_probs.append((Action(ActionType.END_PLAYER_TURN), 1))

        ball = game.get_ball()

        ball_on_floor_pos = game.get_ball(
        ).position if not ball.is_carried else None
        opp_ball_carrier = ball_carrier if ball_carrier is not None and ball_carrier.team is not game.active_team else None

        is_home = player.team is game.state.home_team

        for pos in action_choice.positions:
            prob = 1
            if ball_on_floor_pos is not None:
                if pos == ball_on_floor_pos:
                    prob = 3
                elif pos.distance(ball_on_floor_pos) == 1:
                    prob = 2
            elif opp_ball_carrier is not None and pos.distance(
                    opp_ball_carrier.position):
                prob = 2

            elif is_ball_carrier and game.arena.is_in_opp_endzone(
                    pos, is_home):
                prob = 2

            action = Action(ActionType.MOVE, position=pos)
            action_probs.append((action, prob))

        return action_probs
Beispiel #19
0
def test_set_new_root():
    game, (player1, player2,
           opp_player) = get_custom_game_turn(player_positions=[(5, 5),
                                                                (6, 6)],
                                              opp_player_positions=[(4, 4)],
                                              ball_position=(5, 5),
                                              pathfinding_enabled=True,
                                              forward_model_enabled=True)

    action_p2_1 = Action(ActionType.START_BLITZ, position=player2.position)
    action_p2_2 = Action(ActionType.BLOCK, position=Square(4, 4))

    action_p1_1 = Action(ActionType.START_MOVE, position=player1.position)
    action_p1_2 = Action(ActionType.MOVE, position=Square(1, 5))

    tree = SearchTree(deepcopy(game))
    assert tree.root_node.depth == 0

    # Move player 2
    new_node, = tree.expand_action_node(tree.root_node, action_p2_1)
    new_nodes = tree.expand_action_node(new_node, action_p2_2)

    assert new_node.depth == 1
    assert new_nodes[0].depth == 2
    assert len(tree.all_action_nodes) == 2 + 4

    # Move player 1
    new_node, = tree.expand_action_node(tree.root_node, action_p1_1)
    assert len(tree.all_action_nodes) == 2 + 4 + 1
    new_nodes = tree.expand_action_node(new_node, action_p1_2)

    assert new_node.depth == 1
    assert new_nodes[0].depth == 2
    assert len(tree.all_action_nodes) == 2 + 4 + 1 + 7

    game.step(action_p1_1)
    tree.set_new_root(game)

    assert len(tree.all_action_nodes) == 8
    assert new_node is tree.root_node
    assert new_node.depth == 0
    assert new_nodes[0].depth == 1

    with only_fixed_rolls(game, d6=[6]):
        game.step(action_p1_2)

    tree.set_new_root(game)
    tree.expand_action_node(tree.root_node,
                            Action(ActionType.SETUP_FORMATION_SPREAD))
    assert new_nodes[0] is tree.root_node
    assert len(tree.all_action_nodes) == 2

    game.step(Action(ActionType.SETUP_FORMATION_SPREAD))
    game.step(Action(ActionType.END_SETUP))
    tree.set_new_root(game)
    assert len(tree.all_action_nodes) == 1
    assert len(tree.root_node.children) == 0
Beispiel #20
0
    def setup(self, game):
        """
        Use either a Wedge offensive formation or zone defensive formation.
        """
        # Update teams
        self.my_team = game.get_team_by_id(self.my_team.team_id)
        self.opp_team = game.get_opp_team(self.my_team)

        if self.setup_actions:
            action = self.setup_actions.pop(0)
            return action
        else:
            if game.get_receiving_team() == self.my_team:
                self.setup_actions = self.off_formation.actions(
                    game, self.my_team)
                self.setup_actions.append(Action(ActionType.END_SETUP))
            else:
                self.setup_actions = self.def_formation.actions(
                    game, self.my_team)
                self.setup_actions.append(Action(ActionType.END_SETUP))
            action = self.setup_actions.pop(0)
            return action
Beispiel #21
0
 def player_action(self, game):
     # Execute planned actions if any
     if len(self.actions) > 0:
         action = self._get_next_action()
         return action
     ball_carrier = game.get_ball_carrier()
     if ball_carrier == game.get_active_player():
         td_path = pf.get_safest_path_to_endzone(game, ball_carrier)
         if td_path is not None and td_path.prob <= 0.9:
             self.actions.extend(
                 path_to_move_actions(game, ball_carrier, td_path))
             #print(f"Scoring with {ball_carrier.role.name}, p={td_path.prob}")
             return self._get_next_action()
     return Action(ActionType.END_PLAYER_TURN)
Beispiel #22
0
    def turn(self, game):
        """
        Start a new player action.
        """
        # Update teams
        self.my_team = game.get_team_by_id(self.my_team.team_id)
        self.opp_team = game.get_opp_team(self.my_team)

        # Reset actions if new turn
        turn = game.get_agent_team(self).state.turn
        half = game.state.half
        if half > self.last_half or turn > self.last_turn:
            self.actions.clear()
            self.last_turn = turn
            self.last_half = half
            self.actions = []
            #print(f"Half: {half}")
            #print(f"Turn: {turn}")

        # End turn if only action left
        if len(game.state.available_actions) == 1:
            if game.state.available_actions[
                    0].action_type == ActionType.END_TURN:
                self.actions = [Action(ActionType.END_TURN)]

        # Execute planned actions if any
        while len(self.actions) > 0:
            action = self._get_next_action()
            if game._is_action_allowed(action):
                return action

        # Split logic depending on offense, defense, and loose ball - and plan actions
        ball_carrier = game.get_ball_carrier()
        self._make_plan(game, ball_carrier)
        action = self._get_next_action()
        return action
Beispiel #23
0
 def coin_toss_kick_receive(self, game):
     """
     Select heads/tails and/or kick/receive
     """
     return Action(ActionType.RECEIVE)
Beispiel #24
0
 def blood_lust_block_or_move(self, game):
     return Action(ActionType.START_BLOCK)
Beispiel #25
0
 def eat_thrall(self, game):
     position = game.get_available_actions()[0].positions[0]
     return Action(ActionType.SELECT_PLAYER, position)
Beispiel #26
0
 def use_bribe(self, game):
     return Action(ActionType.USE_BRIBE)
Beispiel #27
0
 def use_pro(self, game):
     return Action(ActionType.USE_SKILL)
Beispiel #28
0
 def use_stand_firm(self, game):
     return Action(ActionType.USE_SKILL)
Beispiel #29
0
 def use_wrestle(self, game):
     return Action(ActionType.USE_SKILL)
Beispiel #30
0
 def use_juggernaut(self, game):
     return Action(ActionType.USE_SKILL)