def test_raise_exception_for_winner_in_running_game(self):
        player = Player(1, 0, 0, Direction.up, 0, True, "Name")
        cells = [[Cell([player]), Cell()]]
        game = Game(2, 1, cells, [player], 1, True, datetime.now())

        with self.assertRaises(Exception):
            game.get_winner()
    def test_return_no_winner_in_ended_game(self):
        player1 = Player(1, 0, 0, Direction.up, 0, False, "Name")
        player2 = Player(1, 1, 0, Direction.up, 0, False, "Name")
        cells = [[Cell([player1]), Cell([player2])]]
        game = Game(2, 1, cells, [player1, player2], 1, False, datetime.now())

        result = game.get_winner()

        self.assertEqual(None, result)
Exemple #3
0
    def update(self, game: Game):
        """See base class."""
        if not self._interface_initialized:
            self._initialize_interface(game)

        print("Round : ", self.__round)
        self.__round += 1

        table_player_ids = []
        for row in range(len(game.cells)):
            row_cells = []
            for col in range(len(game.cells[0])):
                cell = game.cells[row][col]
                if cell.get_player_id() == 0:
                    row_cells.append(' ')
                else:
                    player = game.get_player_by_id(cell.get_player_id())
                    color = self._player_colors[self.__player_representation[
                        cell.get_player_id()]]
                    if player.x == col and player.y == row:
                        if player == game.you:
                            row_cells.append(colored("x", color))
                        else:
                            row_cells.append(colored("o", color))
                    else:
                        row_cells.append(
                            colored(
                                str(self.__player_representation[player.id]),
                                color))
            table_player_ids.append(row_cells)

        print(
            tabulate(table_player_ids, tablefmt="jira").replace(
                " ", "").replace("||", "| |").replace("||", "| |"))

        if not game.running:
            player = game.get_winner()
            if player is None:
                print("No winner in game.")
            else:
                print("Winner: Player " +
                      str(self.__player_representation[player.id]) + " (" +
                      player.name + "). Your player ID was " +
                      str(self.__player_representation[game.you.id]))
Exemple #4
0
    def update(self, game: Game):
        """See base class."""
        if not self._interface_initialized:
            self._initialize_interface(game)

        if not game.running:
            player = game.get_winner()
            if player is None:
                print("No winner in game.")
            else:
                print("Winner: Player " + str(player.id) + " (" + player.name + "). Your player ID was " +
                      str(game.you.id) + ".")

        self.__screen.fill((0, 0, 0))  # black background
        for row in range(game.height):
            for col in range(game.width):
                self.__pygame.draw.rect(self.__screen,
                                        self.__get_player_color(game.cells[row][col]),
                                        (col * self.RECT_SIZE + col,
                                         row * self.RECT_SIZE + row,
                                         self.RECT_SIZE,
                                         self.RECT_SIZE))
                if game.cells[row][col].get_player_id() != 0:
                    player = game.get_player_by_id(game.cells[row][col].get_player_id())
                    if player.x == col and player.y == row:  # print head
                        border_width = 2
                        if player == game.you:
                            border_width = 4  # head of the own player has a smaller dot
                        self.__pygame.draw.rect(self.__screen,
                                                self._player_colors[0],
                                                (col * self.RECT_SIZE + col + border_width,
                                                 row * self.RECT_SIZE + row + border_width,
                                                 self.RECT_SIZE - (2 * border_width),
                                                 self.RECT_SIZE - (2 * border_width)))
        self.__pygame.display.update()
        self.__clock.tick(60)
class AIEvaluationController(OfflineController):
    """Executes multiple games after each other with randomly created games and players.

    The result of every game and the execution time for each player in each round is saved in an SQLite database."""
    def __init__(self, runs: int, db_path: str, evaluation_type: int):
        """ Creates a new AI evaluation controller.

        Args:
            runs: The number of games to be simulated.
            db_path: The path of the SQLite database file.
            evaluation_type: Defines which evaluation should be performed
        """
        super().__init__(HeadlessView())
        self.__runs = runs
        self.__db_path = db_path
        if 1 <= evaluation_type <= 2:
            self.__evaluation_type = evaluation_type
        else:
            self.__evaluation_type = 1
        self.__connection = None
        self.__cursor = None
        self.__current_game_id = None

    def play(self):
        """See base class."""
        with closing(sqlite3.connect(self.__db_path)) as connection:
            with closing(connection.cursor()) as cursor:
                self.__connection = connection
                self.__cursor = cursor

                self.__create_db_tables()

                max_game_id = self.__cursor.execute(
                    "SELECT MAX(id) FROM games").fetchone()[0]
                if max_game_id is None:
                    max_game_id = 0

                self.__run_simulations(max_game_id)

    def _create_game(self) -> None:
        height = randint(30, 70)
        width = randint(30, 70)

        player_count = randint(3, 6)
        players = []
        occupied_coordinates = []
        for i in range(1, player_count + 1):
            next_coordinate = (randint(0, width - 1), randint(0, height - 1))
            while next_coordinate in occupied_coordinates:
                next_coordinate = (randint(0,
                                           width - 1), randint(0, height - 1))
            occupied_coordinates.append(next_coordinate)
            player = Player(i, next_coordinate[0], next_coordinate[1],
                            Direction.get_random_direction(), 1, True, str(i))
            players.append(player)

        cells = [[Cell() for _ in range(width)] for _ in range(height)]
        for player in players:
            cells[player.y][player.x] = Cell([player])

        self._game = Game(width, height, cells, players, 1, True,
                          datetime.now() + timedelta(5, 15))
        self._game_round = 0

        self._ais = []

        if self.__evaluation_type == 1:
            self.__generate_ais_for_first_evaluation(player_count, players)
        elif self.__evaluation_type == 2:
            self.__generate_ais_for_second_evaluation(player_count, players)

    def __generate_ais_for_first_evaluation(self, player_count: int,
                                            players: List[Player]) -> None:
        self._ais.append(
            PathfindingAI(players[0], randint(1, 3),
                          randint(1, 3) * 25))
        self._ais.append(
            PathfindingSearchTreeAI(players[1], randint(1, 3),
                                    randint(1, 3) * 25, randint(2, 3), 0.75,
                                    randint(1, 3) * 10))
        self._ais.append(
            SearchTreePathfindingAI(players[2], randint(1, 3),
                                    randint(1, 3) * 25, 2,
                                    randint(1, 3) * 10))
        if player_count > 3:
            self._ais.append(
                SearchTreeAI(players[3], randint(1, 3), randint(2, 3), True,
                             randint(1, 3) * 10))
            if player_count > 4:
                self._ais.append(
                    NotKillingItselfAI(players[4], [AIOptions.max_distance],
                                       randint(1, 3), 0, randint(1, 3)))
                if player_count > 5:
                    self._ais.append(RandomAI(players[5], randint(1, 3)))

    def __generate_ais_for_second_evaluation(self, player_count: int,
                                             players: List[Player]) -> None:
        used_ai_indices = []
        for i in range(player_count):
            ai_index = randint(0, len(best_ais_configurations) - 1)
            # Prevent that the same AI configuration is used in one game
            while ai_index in used_ai_indices:
                ai_index = randint(0, len(best_ais_configurations) - 1)

            used_ai_indices.append(ai_index)
            ai = best_ais_configurations[ai_index]
            self._ais.append(globals()[ai[0]](players[i], *ai[1]))

    def __run_simulations(self, max_game_id):
        for i in range(self.__runs):
            self.__current_game_id = i + 1 + max_game_id
            super().play()

            self.__cursor.execute(
                "INSERT INTO games VALUES ({}, {}, {}, '{}', NULL)".format(
                    self.__current_game_id, self._game.width,
                    self._game.height, datetime.now(timezone.utc)))

            winner_player = self._game.get_winner()
            for ai in self._ais:
                ai_class = ai.__class__.__name__
                ai_info = ai.get_information()
                player_id = self.__get_player_id(ai_class, ai_info)

                # Save how often an AI configuration participated in a game
                self.__cursor.execute(
                    "INSERT INTO participants VALUES ({}, {})".format(
                        player_id, self.__current_game_id))

                # Save how often an AI configuration won a game
                if ai.player == winner_player:
                    self.__cursor.execute(
                        "UPDATE games SET winner_id = {} WHERE id = {}".format(
                            player_id, self.__current_game_id))

            self.__connection.commit()

    def __create_db_tables(self):
        self.__cursor.execute("CREATE TABLE IF NOT EXISTS players ("
                              "id INTEGER NOT NULL PRIMARY KEY,"
                              "class TEXT NOT NULL,"
                              "info TEXT)")
        self.__cursor.execute(
            "CREATE TABLE IF NOT EXISTS games ("
            "id INTEGER NOT NULL PRIMARY KEY,"
            "width INTEGER NOT NULL,"
            "height INTEGER NOT NULL,"
            "date TEXT NOT NULL,"
            "winner_id INTEGER,"
            "FOREIGN KEY (winner_id) REFERENCES players (id))")
        self.__cursor.execute(
            "CREATE TABLE IF NOT EXISTS participants ("
            "player_id INTEGER NOT NULL,"
            "game_id INTEGER NOT NULL,"
            "PRIMARY KEY(player_id, game_id),"
            "FOREIGN KEY (player_id) REFERENCES players (id),"
            "FOREIGN KEY (game_id) REFERENCES games (id))")
        self.__cursor.execute(
            "CREATE TABLE IF NOT EXISTS execution_times ("
            "player_id INTEGER NOT NULL,"
            "game_id INTEGER NOT NULL,"
            "game_round INTEGER NOT NULL,"
            "execution REAL NOT NULL,"
            "PRIMARY KEY(player_id, game_id, game_round),"
            "FOREIGN KEY (player_id) REFERENCES players (id),"
            "FOREIGN KEY (game_id) REFERENCES games (id))")

    def _log_execution_time(self, ai: ArtificialIntelligence,
                            execution_time: float):
        ai_class = ai.__class__.__name__
        ai_info = ai.get_information()
        player_id = self.__get_player_id(ai_class, ai_info)

        self.__cursor.execute(
            "INSERT INTO execution_times VALUES ({}, {}, {}, {})".format(
                player_id, self.__current_game_id, self._game_round,
                execution_time))

    def __get_player_id(self, ai_class: str, ai_info: str) -> int:
        player_id = self.__cursor.execute(
            "SELECT MAX(id) FROM players p WHERE p.class = '{}' AND p.info = '{}'"
            .format(ai_class, ai_info)).fetchone()[0]

        if player_id is None:
            max_player_id = self.__cursor.execute(
                "SELECT MAX(id) FROM players").fetchone()[0]
            if max_player_id is None:
                max_player_id = 0
            player_id = max_player_id + 1
            self.__cursor.execute(
                "INSERT INTO players VALUES ({}, '{}', '{}')".format(
                    player_id, ai_class, ai_info))

        return player_id