示例#1
0
 def __perform_simulation(game_service: GameService, action: Action, player: Player):
     if player.active:
         try:
             game_service.visited_cells_by_player[player.id] = \
                 game_service.get_and_visit_cells(player, action)
         except InvalidPlayerMoveException:
             game_service.set_player_inactive(player)
示例#2
0
    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)
示例#4
0
    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())
示例#5
0
    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
示例#6
0
    def calc_action_with_max_distance_to_visited_cells(
            self, game_service: GameService,
            actions: List[Action]) -> List[Action]:
        """Calculates a list of actions that have the property to have as many free cells as possible in front of them
        while running straight after the action has been executed.

        Args:
            game_service: The game service used for simulation of actions.
            actions: The actions to be checked

        Returns:
            List of best actions with the property having as many free cells as possible in front of the player.
        """
        max_straight_distance = 0
        best_actions: Dict[Action, int] = {}
        for action in actions:
            gs_copy = copy.deepcopy(game_service)
            try:
                player = gs_copy.game.get_player_by_id(self.player.id)
                gs_copy.visited_cells_by_player[
                    player.id] = gs_copy.get_and_visit_cells(player, action)

                straight_distance = 0
                horizontal_multiplier, vertical_multiplier = GameService.get_horizontal_and_vertical_multiplier(
                    player)

                for i in range(max(gs_copy.game.height, gs_copy.game.width)):
                    x = player.x + (i + 1) * horizontal_multiplier
                    y = player.y + (i + 1) * vertical_multiplier
                    if x in range(gs_copy.game.width) and y in range(
                            gs_copy.game.height) and (
                                gs_copy.game.cells[y][x].players is None
                                or len(gs_copy.game.cells[y][x].players) == 0):
                        straight_distance += 1
                    else:
                        break

                if len(best_actions
                       ) == 0 or straight_distance > max_straight_distance:
                    max_straight_distance = straight_distance
                    best_actions[action] = straight_distance
                    updated_best_actions: Dict[Action, int] = {}
                    for (act, dist) in best_actions.items(
                    ):  # new max_straight_distance. Remove worth options
                        if dist >= max_straight_distance - self.__max_worse_distance:
                            updated_best_actions[act] = dist
                    best_actions = updated_best_actions
                elif straight_distance >= max_straight_distance - self.__max_worse_distance:  # still good option
                    best_actions[action] = straight_distance
            except InvalidPlayerMoveException as ex:
                logging.warning(ex)
                continue

        return list(best_actions.keys())
    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)
示例#8
0
    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()
示例#9
0
    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 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)
示例#15
0
    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()
class GameTest(unittest.TestCase):

    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 test_game_should_end_when_less_than_two_players_are_left(self):
        self.player1.active = False
        self.player2.active = False

        self.assertEqual(self.sut.is_game_running(), False)

    def test_game_should_not_end_when_more_than_one_players_are_left(self):
        self.player1.active = False

        self.assertEqual(self.sut.is_game_running(), True)

    def test_player_should_loose_if_he_did_more_than_one_action_in_one_round(self):
        self.sut.do_action(self.player1, Action.speed_up)
        self.sut.do_action(self.player1, Action.speed_up)

        self.assertEqual(self.player1.active, False)

    def test_player_should_not_loose_if_he_did_exactly_one_action_in_one_round(self):
        self.sut.do_action(self.player1, Action.speed_up)

        self.assertEqual(self.player1.active, True)

    def test_visited_cells_should_be_calculated_correctly_turn_1_to_5(self):
        self.player1.direction = Direction.down
        self.player1.speed = 1
        player1_x = self.player1.x
        player1_y = self.player1.y
        self.game.cells[self.player1.y][self.player1.x] = Cell([self.player1])
        self.player2.direction = Direction.up
        self.player2.speed = 3
        player2_x = self.player2.x
        player2_y = self.player2.y
        self.game.cells[self.player2.y][self.player2.x] = Cell([self.player2])
        self.player3.direction = Direction.down
        self.player3.speed = 5
        player3_x = self.player3.x
        player3_y = self.player3.y
        self.game.cells[self.player3.y][self.player3.x] = Cell([self.player3])
        visited_cells_p1_expected = [(player1_x, player1_y + 1), (player1_x, player1_y + 2)]
        visited_cells_p2_expected = [(player2_x, player2_y - 1), (player2_x, player2_y - 2)]
        visited_cells_p3_expected = [(player3_x + 1, player3_y), (player3_x + 2, player3_y), (player3_x + 3, player3_y),
                                     (player3_x + 4, player3_y), (player3_x + 5, player3_y)]

        visited_cells_p1 = self.sut.get_and_visit_cells(self.player1, Action.speed_up)
        visited_cells_p2 = self.sut.get_and_visit_cells(self.player2, Action.slow_down)
        visited_cells_p3 = self.sut.get_and_visit_cells(self.player3, Action.turn_left)

        self.assertEqual(visited_cells_p1_expected, visited_cells_p1)
        self.assertEqual(visited_cells_p2_expected, visited_cells_p2)
        self.assertEqual(visited_cells_p3_expected, visited_cells_p3)
        self.assertTrue(self.player1 in self.game.cells[player1_y + 1][player1_x].players)
        self.assertTrue(self.player1 in self.game.cells[player1_y + 2][player1_x].players)
        self.assertTrue(self.player2 in self.game.cells[player2_y - 2][player2_x].players)
        self.assertTrue(self.player2 in self.game.cells[player2_y - 2][player2_x].players)
        self.assertTrue(self.player3 in self.game.cells[player3_y][player3_x + 1].players)
        self.assertTrue(self.player3 in self.game.cells[player3_y][player3_x + 2].players)
        self.assertTrue(self.player3 in self.game.cells[player3_y][player3_x + 3].players)
        self.assertTrue(self.player3 in self.game.cells[player3_y][player3_x + 4].players)
        self.assertTrue(self.player3 in self.game.cells[player3_y][player3_x + 5].players)

    def test_visited_cells_should_be_calculated_correctly_turn_6(self):
        self.sut.turn.turn_ctr = 12  # 6, 12, 18 should all work
        self.player1.direction = Direction.down
        self.player1.speed = 1
        player1_x = self.player1.x
        player1_y = self.player1.y
        self.game.cells[10][10] = Cell([self.player1])
        self.player2.direction = Direction.up
        self.player2.speed = 5
        player2_x = self.player2.x
        player2_y = self.player2.y
        self.game.cells[10][30] = Cell([self.player2])
        visited_cells_p1_expected = [(player1_x, player1_y + 1), (player1_x, player1_y + 2)]
        visited_cells_p2_expected = [(player2_x, player2_y - 1), (player2_x, player2_y - 6)]

        visited_cells_p1 = self.sut.get_and_visit_cells(self.player1, Action.speed_up)
        visited_cells_p2 = self.sut.get_and_visit_cells(self.player2, Action.speed_up)

        self.assertEqual(visited_cells_p1_expected, visited_cells_p1)
        self.assertEqual(visited_cells_p2_expected, visited_cells_p2)
        self.assertTrue(self.player1 in self.game.cells[player1_y + 1][player1_x].players)
        self.assertTrue(self.player1 in self.game.cells[player1_y + 2][player1_x].players)
        self.assertTrue(self.player2 in self.game.cells[player2_y - 1][player2_x].players)
        self.assertTrue(self.player2 in self.game.cells[player2_y - 6][player2_x].players)

    def test_game_cells_should_be_correct_after_collision(self):
        self.player1.direction = Direction.left
        self.player1.speed = 4
        self.player1.x = 2
        self.player1.y = 0
        self.game.cells[self.player1.y][self.player1.x] = Cell([self.player1])
        self.game.cells[self.player1.y][1] = Cell([self.player1])

        self.sut.get_and_visit_cells(self.player1, Action.speed_up)

        self.assertEqual(self.player1.x, 0)
        self.assertEqual(self.player1.y, 0)
        self.assertTrue(self.player1 in self.game.cells[0][0].players)
        self.assertTrue(self.player1 in self.game.cells[0][1].players)
        self.assertTrue(self.player1 in self.game.cells[0][2].players)

    def test_visited_cells_should_be_correct_after_collision(self):
        self.player1.direction = Direction.left
        self.player1.speed = 4
        self.player1.x = 2
        self.player1.y = 0
        self.game.cells[self.player1.y][self.player1.x] = Cell([self.player1])
        self.game.cells[self.player1.y][1] = Cell([self.player1])

        visited_cells = self.sut.get_and_visit_cells(self.player1, Action.speed_up)

        self.assertEqual(self.player1.x, 0)
        self.assertEqual(self.player1.y, 0)
        self.assertTrue((0, 0) in visited_cells)
        self.assertTrue((1, 0) in visited_cells)

    def test_playerX_playerY_should_be_correct_after_collision(self):
        self.player1.direction = Direction.left
        self.player1.speed = 2
        self.player1.x = 1
        self.player1.y = 0
        self.game.cells[self.player1.y][self.player1.x] = Cell([self.player1])

        self.sut.get_and_visit_cells(self.player1, Action.speed_up)

        self.assertEqual(self.player1.x, 0)
        self.assertEqual(self.player1.y, 0)

    def test_playerX_playerY_should_be_correct_without_collision(self):
        self.player1.direction = Direction.left
        self.player1.speed = 2
        self.player1.x = 10
        self.player1.y = 0
        self.game.cells[self.player1.y][self.player1.x] = Cell([self.player1])

        self.sut.get_and_visit_cells(self.player1, Action.change_nothing)

        self.assertEqual(self.player1.x, 8)
        self.assertEqual(self.player1.y, 0)

    def test_correct_multiplier_should_be_returned_direction_up(self):
        self.player1.direction = Direction.up

        self.assertEqual((0, -1), self.sut.get_horizontal_and_vertical_multiplier(self.player1))

    def test_correct_multiplier_should_be_returned_direction_down(self):
        self.player1.direction = Direction.down

        self.assertEqual((0, 1), self.sut.get_horizontal_and_vertical_multiplier(self.player1))

    def test_correct_multiplier_should_be_returned_direction_left(self):
        self.player1.direction = Direction.left

        self.assertEqual((-1, 0), self.sut.get_horizontal_and_vertical_multiplier(self.player1))

    def test_correct_multiplier_should_be_returned_direction_right(self):
        self.player1.direction = Direction.right

        self.assertEqual((1, 0), self.sut.get_horizontal_and_vertical_multiplier(self.player1))