From 181c7693ede98d05d8bf0bcda5eba7a0ce9be47f Mon Sep 17 00:00:00 2001 From: mattias bermell Date: Tue, 27 Jun 2023 20:42:48 +0200 Subject: [PATCH 1/3] shuffle positional actions when creating ActionChoice --- botbowl/core/model.py | 28 ++++++++++++++--- examples/scripted_bot_brawl.py | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 examples/scripted_bot_brawl.py diff --git a/botbowl/core/model.py b/botbowl/core/model.py index 9e6499ac..481c489b 100755 --- a/botbowl/core/model.py +++ b/botbowl/core/model.py @@ -614,6 +614,11 @@ def to_json(self): 'bomb': self.bomb.to_json() if self.bomb else None } +def permute_list(l: Optional[list], permutation: np.ndarray): + if l is None or len(l) == 0: + return [] + assert len(l) == len(permutation), f"Length of list {l} does not match length of permutation {permutation}" + return [l[i] for i in permutation] @immutable_after_init class ActionChoice: @@ -629,15 +634,28 @@ class ActionChoice: def __init__(self, action_type, team, positions=None, players=None, rolls=None, block_dice=None, skill=None, paths=None, disabled=False): + self.action_type = action_type - self.positions = [] if positions is None else positions - self.players = [] if players is None else players self.team = team - self.rolls = [] if rolls is None else rolls - self.block_dice = [] if block_dice is None else block_dice self.disabled = disabled self.skill = skill - self.paths = [] if paths is None else paths + if positions is not None: + permutation_indices = np.random.permutation(len(positions)) + try: + self.positions = permute_list(positions, permutation_indices) + self.rolls = permute_list(rolls, permutation_indices) + self.block_dice = permute_list(block_dice, permutation_indices) + self.paths = permute_list(paths, permutation_indices) + except AssertionError as e: + new_message = str(e) + f" with action type {action_type}" + raise type(e)(new_message) + else: + self.positions = [] if positions is None else positions + self.rolls = [] if rolls is None else rolls + self.block_dice = [] if block_dice is None else block_dice + self.paths = [] if paths is None else paths + self.players = [] if players is None else players + def __repr__(self): return f"ActionChoice({self.action_type}, len(positions)={len(self.positions)}, " \ diff --git a/examples/scripted_bot_brawl.py b/examples/scripted_bot_brawl.py new file mode 100644 index 00000000..8ff9e1cf --- /dev/null +++ b/examples/scripted_bot_brawl.py @@ -0,0 +1,56 @@ +import botbowl +import time +import scripted_bot_example + + +def main(): + # Load configurations, rules, arena and teams + config = botbowl.load_config("bot-bowl") + config.competition_mode = False + config.pathfinding_enabled = True + # config = get_config("gym-7.json") + # config = get_config("gym-5.json") + # config = get_config("gym-3.json") + ruleset = botbowl.load_rule_set( + config.ruleset, all_rules=False + ) # We don't need all the rules + arena = botbowl.load_arena(config.arena) + home = botbowl.load_team_by_filename("human", ruleset) + away = botbowl.load_team_by_filename("human", ruleset) + + num_games = 1000 + home_tds = 0 + away_tds = 0 + home_wins = 0 + away_wins = 0 + draws = 0 + # Play 10 games + for i in range(num_games): + home_agent = botbowl.make_bot("scripted") + home_agent.name = "Scripted Bot (home)" + away_agent = botbowl.make_bot("scripted") + away_agent.name = "Scripted (away)" + config.debug_mode = False + game = botbowl.Game( + i, home, away, home_agent, away_agent, config, arena=arena, ruleset=ruleset + ) + game.config.fast_mode = True + + print("Starting game", (i + 1)) + start = time.time() + game.init() + end = time.time() + print(end - start) + + home_wins += 1 if game.get_winning_team() is game.state.home_team else 0 + away_wins += 1 if game.get_winning_team() is game.state.away_team else 0 + home_tds += game.state.home_team.state.score + away_tds += game.state.away_team.state.score + + print( + f"(home, away): Wins: ({home_wins}, {away_wins}), TDs: ({home_tds}, {away_tds})" + ) + + +if __name__ == "__main__": + main() From 9d8d277585add0d30d0c7aca192e65f69cb5d27b Mon Sep 17 00:00:00 2001 From: mattias bermell Date: Tue, 27 Jun 2023 20:43:07 +0200 Subject: [PATCH 2/3] shut scripted bot up! --- examples/scripted_bot_example.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/examples/scripted_bot_example.py b/examples/scripted_bot_example.py index e306a9e7..92aff6ad 100755 --- a/examples/scripted_bot_example.py +++ b/examples/scripted_bot_example.py @@ -682,16 +682,6 @@ def end_game(self, game): """ Called when a game ends. """ - winner = game.get_winning_team() - print("Casualties: ", game.num_casualties()) - if winner is None: - print("It's a draw") - elif winner == self.my_team: - print("I ({}) won".format(self.name)) - print(self.my_team.state.score, "-", self.opp_team.state.score) - else: - print("I ({}) lost".format(self.name)) - print(self.my_team.state.score, "-", self.opp_team.state.score) def path_to_move_actions(game: botbowl.Game, player: botbowl.Player, path: Path, do_assertions=True) -> List[Action]: @@ -791,4 +781,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() From fc9667334dd30e25841993b0ae69b4decbd01faa Mon Sep 17 00:00:00 2001 From: mattias bermell Date: Tue, 27 Jun 2023 21:39:43 +0200 Subject: [PATCH 3/3] disallow all Block actions --- botbowl/core/game.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/botbowl/core/game.py b/botbowl/core/game.py index 0e001a7b..6356a7ad 100755 --- a/botbowl/core/game.py +++ b/botbowl/core/game.py @@ -650,7 +650,11 @@ def set_available_actions(self) -> None: Calls the current procedure's available_actions() method and sets the game's available actions to the returned list. """ - self.state.available_actions = self.state.stack.peek().available_actions() + forbidden_actions_types = {ActionType.BLOCK} + actions = self.state.stack.peek().available_actions() + if actions is not None: + actions = [action for action in actions if action.action_type not in forbidden_actions_types ] + self.state.available_actions = actions def report(self, outcome) -> None: """