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)
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]))
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