def play(self): """See base class.""" self._create_game() game_service = GameService(self._game, ignore_deadline=False) self._view.update(self._game) while self._game.running: self._game_round += 1 time_to_react = randint(4, 16) self.__reset_game_deadline(time_to_react) # Read input from user if there is a human player player_action = None if self.__you is not None and self.__you.active: player_action = self._view.read_next_action() if datetime.now(time_zone) > self._game.deadline: player_action = Action.get_default() self.__reset_game_deadline(time_to_react) for ai in self._ais: if ai is not None and ai.player.active: action = self.__choose_ai_action(ai, time_to_react) game_service.do_action(ai.player, action) self.__reset_game_deadline(time_to_react) # Perform action of human player after AIs finished their calculations # Otherwise the AIs would already know the players move if self.__you is not None and player_action is not None: game_service.do_action(self.__you, player_action) self._view.update(self._game)
def __create_child(self, player: Player, action: Action, turn_counter: int, max_speed: int): if player.speed == max_speed and action == Action.speed_up: return modified_game = self._game.copy() game_service = GameService(modified_game) game_service.turn.turn_ctr = turn_counter SearchTreeRoot.__perform_simulation(game_service, action, modified_game.get_player_by_id(player.id)) game_service.check_and_set_died_players() return SearchTreeNode(modified_game.copy(), action)
def setUp(self): self.player1 = Player(1, 10, 10, Direction.down, 1, True, "") self.player2 = Player(2, 10, 30, Direction.down, 3, True, "") self.player3 = Player(3, 30, 10, Direction.right, 2, True, "Name 3") players = [self.player1, self.player2, self.player3] cells = [[Cell() for _ in range(40)] for _ in range(40)] cells[self.player1.y][self.player1.x] = Cell([self.player1]) cells[self.player2.y][self.player2.x] = Cell([self.player2]) cells[self.player3.y][self.player3.x] = Cell([self.player3]) time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) self.game = Game(40, 40, cells, players, 2, True, time) self.sut = GameService(self.game)
def __try_combination(game: Game, player_ids_to_watch: List[int], combination: Tuple[Action], turn_counter: int): modified_game = game.copy() game_service = GameService(modified_game) game_service.turn.turn_ctr = turn_counter players = modified_game.get_players_by_ids(player_ids_to_watch) for j in range(len(combination)): action = combination[j] player = players[j] SearchTreeRoot.__perform_simulation(game_service, action, player) game_service.check_and_set_died_players() return SearchTreeRoot(modified_game.copy())
def create_next_action(self, game: Game, return_value: Value): """See base class.""" self._turn_ctr += 1 surviving_actions = self.create_all_next_surviving_actions(game) if surviving_actions is not None and len(surviving_actions) > 0: return_value.value = choice(surviving_actions).get_index() return_value.value = self.find_actions_by_best_path_connection( surviving_actions, game)[0][0].get_index() else: surviving_pathfinding_actions = self.find_actions_by_best_path_connection( self.find_surviving_actions(GameService(game), 1), game) return_value.value = surviving_pathfinding_actions[0][0].get_index() \ if surviving_pathfinding_actions is not None and len(surviving_pathfinding_actions) > 0 \ else Action.get_default().get_index()
def create_next_actions_ranked(self, game: Game) -> Optional[List[Tuple[Action, int]]]: """Calculates all actions with the number of reachable paths, with which the AI won't lose in the next turn. Args: game: The game object in which the AI is located and which contains the current status of the game. Returns: A list with actions and the corresponding number of accessible paths. """ game_service = GameService(game) game_service.turn.turn_ctr = self._turn_ctr surviving_actions = self.find_surviving_actions_with_best_depth(game_service) return self.find_actions_by_best_path_connection(surviving_actions, game)
def find_actions_by_best_path_connection(self, actions: List[Action], game: Game) -> Optional[ List[Tuple[Action, int]]]: """ Calculates for the passed actions how many paths are still accessible after the execution of the action. For this purpose, points are randomly generated on the playing field and an algorithm for finding paths is used to check whether the point can be reached. Args: actions: List of actions to check. game: The game that contains the current state of the game. Returns: List of actions with the accessible paths. """ if actions is None or len(actions) == 0: return None # shuffle the actions, so that different actions are chosen if they have the same quality and the AI is not so # easily predictable. shuffle(actions) actions_with_possible_paths: List[Tuple[Action, int]] = [] free_cells_for_pathfinding = self.get_random_free_cells_from_playground(game) path_finder = BestFirst(diagonal_movement=DiagonalMovement.never) for action in actions: game_copy = game.copy() game_service = GameService(game_copy) try: player = game_service.game.get_player_by_id(self.player.id) game_service.visited_cells_by_player[player.id] = game_service.get_and_visit_cells(player, action) except InvalidPlayerMoveException: continue matrix = game_copy.translate_cell_matrix_to_pathfinding_matrix() current_possible_paths = 0 length_free_cells = len(free_cells_for_pathfinding) for i in range(length_free_cells): grid = Grid(matrix=matrix) start = grid.node(player.x, player.y) end = grid.node(free_cells_for_pathfinding[i][0], free_cells_for_pathfinding[i][1]) path, _ = path_finder.find_path(start, end, grid) if len(path) > 0: # a path exists current_possible_paths += 1 actions_with_possible_paths.append((action, current_possible_paths)) # Action with most accessible paths at index 0 actions_with_possible_paths.sort(key=operator.itemgetter(1), reverse=True) return actions_with_possible_paths
def test_ai_should_choose_empty_list_with_depth_three_and_no_surviving_action(self): player1 = Player(1, 1, 2, Direction.up, 1, True, "") player2 = Player(2, 1, 1, Direction.down, 3, True, "") players = [player1, player2] cells = [[Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player2]), Cell([player2]), Cell([player2]), Cell(), Cell()], [Cell(), Cell([player1]), Cell(), Cell([player2]), Cell()], [Cell([player2]), Cell([player2]), Cell(), Cell([player2]), Cell()], [Cell(), Cell(), Cell([player2]), Cell(), Cell()]] time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) game = Game(5, 5, cells, players, 2, True, time) game_service = GameService(game) sut = NotKillingItselfAI(player1, [], 3, 0, 3) actions: List[Action] = sut.find_surviving_actions(game_service, 3) self.assertTrue(len(actions) == 0)
def test_ai_should_choose_best_list_of_actions_by_depth(self): player1 = Player(1, 1, 2, Direction.up, 1, True, "") player2 = Player(2, 1, 1, Direction.down, 3, True, "") players = [player1, player2] cells = [[Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player2]), Cell([player2]), Cell([player2]), Cell(), Cell()], [Cell(), Cell([player1]), Cell(), Cell([player2]), Cell()], [Cell([player2]), Cell(), Cell(), Cell([player2]), Cell()], [Cell(), Cell(), Cell([player2]), Cell(), Cell()]] time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) game = Game(5, 5, cells, players, 2, True, time) game_service = GameService(game) sut = NotKillingItselfAI(player1, [], 3, 0, 5) actions: List[Action] = sut.find_surviving_actions_with_best_depth(game_service) self.assertTrue(Action.turn_right in actions) self.assertTrue(len(actions) == 1)
def test_ai_should_not_choose_speed_up_if_max_speed_is_allready_reached(self): MAX_SPEED = 3 player1 = Player(1, 0, 4, Direction.up, MAX_SPEED, True, "") player2 = Player(2, 0, 1, Direction.down, 3, True, "") players = [player1, player2] cells = [[Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player2]), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player1]), Cell(), Cell(), Cell(), Cell()]] time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) game = Game(5, 5, cells, players, 2, True, time) game_service = GameService(game) sut = NotKillingItselfAI(player1, [], MAX_SPEED, 0, 3) actions: List[Action] = sut.find_surviving_actions(game_service, 1) self.assertTrue(Action.slow_down in actions) self.assertTrue(Action.turn_right in actions) self.assertTrue(len(actions) == 2)
def test_ai_should_choose_the_correct_list_of_actions_non_killing_itself(self): player1 = Player(1, 0, 1, Direction.up, 1, True, "") player2 = Player(2, 4, 4, Direction.down, 3, True, "") players = [player1, player2] cells = [[Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player1]), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell([player2])]] time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) game = Game(5, 5, cells, players, 2, True, time) game_service = GameService(game) sut = NotKillingItselfAI(player1, [], 3, 0, 3) actions: List[Action] = sut.find_surviving_actions(game_service, 3) self.assertTrue(Action.change_nothing in actions) self.assertTrue(Action.turn_right in actions) self.assertTrue(len(actions) == 2)
def test_ai_should_calc_action_with_max_distance(self): player1 = Player(1, 0, 4, Direction.up, 1, True, "") player2 = Player(2, 0, 1, Direction.down, 3, True, "") players = [player1, player2] cells = [[Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player2]), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell(), Cell(), Cell(), Cell(), Cell()], [Cell([player1]), Cell(), Cell(), Cell(), Cell()]] time = datetime(2020, 10, 1, 12, 5, 13, 0, timezone.utc) game = Game(5, 5, cells, players, 2, True, time) game_service = GameService(game) sut = NotKillingItselfAI(player1, [], 3, 0, 3) actions: List[Action] = sut.calc_action_with_max_distance_to_visited_cells(game_service, [Action.speed_up, Action.change_nothing, Action.turn_right]) self.assertTrue(Action.turn_right in actions) self.assertTrue(len(actions) == 1)
def create_next_action(self, game: Game, return_value: Value): """See base class.""" self._turn_ctr += 1 game_service = GameService(game) game_service.turn.turn_ctr = self._turn_ctr surviving_actions = self.find_surviving_actions_with_best_depth( game_service) if AIOptions.max_distance in self.__options: max_distance_actions = self.calc_action_with_max_distance_to_visited_cells( game_service, surviving_actions) action = choice( max_distance_actions ) if max_distance_actions is not None and len( max_distance_actions) > 0 else Action.change_nothing else: action = choice( surviving_actions) if surviving_actions is not None and len( surviving_actions) > 0 else Action.change_nothing return_value.value = action.get_index()