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)
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
def get_filtered_available_actions(game: botbowl.Game): allowed_avail_actions = [] disallowed = { ActionType.START_FOUL, ActionType.START_PASS, ActionType.START_HANDOFF } for action_choice in game.get_available_actions(): if action_choice.action_type in disallowed: continue allowed_avail_actions.append(action_choice) return allowed_avail_actions
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
def expand_moving(game: botbowl.Game, parent: Node) -> Node: # noinspection PyTypeChecker active_proc: Union[procedures.GFI, procedures.Dodge] = game.get_procedure() assert type(active_proc) is procedures.Dodge or type( active_proc) is procedures.GFI move_action_proc: procedures.MoveAction = first( proc for proc in reversed(game.state.stack.items) if isinstance(proc, procedures.MoveAction)) is_blitz = type(move_action_proc) is procedures.BlitzAction is_handoff = type(move_action_proc) is procedures.HandoffAction player = move_action_proc.player if move_action_proc.steps is not None: final_step = move_action_proc.steps[-1] else: if is_blitz: block_proc: procedures.Block = first( filter(lambda proc: type(proc) is procedures.Block, game.state.stack.items)) final_step = block_proc.defender.position elif is_handoff: raise ValueError() else: final_step = active_proc.position is_pickup = game.get_ball( ).position == final_step and not game.get_ball().is_carried path = move_action_proc.paths[final_step] """ This block of code sets two important variables: probability_success - probability of the remaining path rolls - list[int] - the remaining rolls of the path Normal case we just fetch this from the path object. If we're in a rerolled proc, it's nasty... """ if active_proc.roll is None: probability_success = path.prob rolls = list(collapse(path.rolls)) if is_pickup: # remove the pickup roll and probability rolls.pop() probability_success /= game.get_pickup_prob( active_proc.player, final_step) else: with only_fixed_rolls(game): game.step() new_proc = game.get_procedure() if type(new_proc) not in {procedures.GFI, procedures.Dodge}: assert not active_proc.reroll.use_reroll return expand_none_action(game, parent) # if we get here, it means that a reroll was used. assert new_proc is active_proc assert active_proc.roll is None assert active_proc.reroll is None current_step = active_proc.position try: assert player.position.distance( current_step) == 1 or is_pickup or is_blitz except AssertionError as e: raise e i = 0 while path.steps[i] != current_step: i += 1 remaining_current_step_rolls = path.rolls[i][:] if is_pickup and current_step == final_step: remaining_current_step_rolls.pop() num_current_step_remaining_rolls = len( list( filter(lambda x: type(x) in {procedures.GFI, procedures.Dodge}, game.state.stack.items))) assert num_current_step_remaining_rolls in [1, 2] remaining_current_step_rolls = remaining_current_step_rolls[ -num_current_step_remaining_rolls:] probability_success = reduce( operator.mul, map(lambda d: (7 - d) / 6, remaining_current_step_rolls), 1.0) rolls = list(collapse(remaining_current_step_rolls)) if current_step != final_step: step_count = game.get_step() if player.position != current_step: try: game.move(player, current_step) except AssertionError as e: raise e new_path = pf.get_safest_path(game, player, final_step, blitz=is_blitz) game.revert(step_count) #try: # # assert new_path.steps == path.steps[-len(new_path):] this assert can't be made because of small randomness in pathfinder # assert list(collapse(new_path.rolls)) == list(collapse(path.rolls[-len(new_path):])), f"{new_path.rolls} != {path.rolls[-len(new_path):]}" #except AssertionError as e: # raise e try: rolls.extend(collapse(new_path.rolls)) except AttributeError as e: raise e probability_success *= new_path.prob if is_pickup: # remove the pickup roll and probability rolls.pop() probability_success /= game.get_pickup_prob( active_proc.player, final_step) try: p = np.array(rolls) / sum(rolls) index_of_failure = np.random.choice(range(len(rolls)), 1, p=p)[0] except ValueError as e: raise e # STEP UNTIL FAILURE (possibly no steps at all) with only_fixed_rolls(game, d6=[6] * index_of_failure): while len(botbowl.D6.FixedRolls) > 0: if len(game.get_available_actions()) > 0: raise AttributeError("wrong") game.step() new_parent = ChanceNode(game, parent) debug_step_count = game.get_step() # SUCCESS SCENARIO with only_fixed_rolls(game, d6=[6] * (len(rolls) - index_of_failure)): while len(botbowl.D6.FixedRolls) > 0: if type(game.get_procedure()) not in { procedures.GFI, procedures.Block, procedures.Dodge, procedures.Move, procedures.MoveAction, procedures.BlitzAction }: raise AttributeError("wrong") if len(game.get_available_actions()) > 0: raise AttributeError("wrong") if type(game.get_procedure() ) is procedures.Block and not game.get_procedure().gfi: raise AttributeError("wrong") game.step() success_node = expand_none_action(game, new_parent, moving_handled=True) new_parent.connect_child(success_node, probability_success) assert debug_step_count == game.get_step() # FAILURE SCENARIO with only_fixed_rolls(game, d6=[1]): while len(botbowl.D6.FixedRolls) > 0: if len(game.get_available_actions()) > 0: raise AttributeError("wrong") game.step() fail_node = expand_none_action(game, new_parent, moving_handled=True) new_parent.connect_child(fail_node, 1 - probability_success) assert debug_step_count == game.get_step() return new_parent