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 do_action(self, player: Player, action: Action): """Performs the action for a player. Additionally it checks if the game is finished and which players have died when a new turn starts. Args: player: The player who wants to perform the action. action: The action to perform. Raises: InvalidPlayerMoveException: The player is outside the field, has reached an invalid player speed or was not allowed to take any further action this turn. """ try: new_turn = self.turn.action(player) action_to_perform = action \ if self.__ignore_deadline or datetime.now(self.game.deadline.tzinfo) <= self.game.deadline \ else Action.get_default() self.visited_cells_by_player[player.id] = self.get_and_visit_cells( player, action_to_perform) if new_turn: self.check_and_set_died_players() except InvalidPlayerMoveException: self.set_player_inactive(player) self.game.running = self.is_game_running()
def test_online_connection_can_be_executed(self, connect_mock): connect_mock.return_value = mock view = Mock() data_loader = Mock() data_loader.load.side_effect = [create_game(True), create_game(False)] data_writer = Mock() data_writer.write.return_value = Action.get_default() controller = OnlineController(view, "", "", "", data_loader, data_writer, PathfindingAI.__name__, (2, 75)) controller.play() view.update.assert_has_calls([call(ANY), call(ANY)], any_order=False) view.end.assert_called_once() data_loader.load.assert_has_calls([call(""), call("")], any_order=False) mock.send.assert_has_calls([call(Action.get_default())])
def test_read_next_action_should_return_correct_action_input_close(self, sys_exit, time_sleep): mock_event = Mock() mock_event.type = pygame_mock.QUIT = 2 pygame_mock.event.get.return_value = [mock_event] result = self.sut.read_next_action() self.assertEqual(Action.get_default(), result) pygame_mock.display.quit.assert_called() pygame_mock.quit.assert_called()
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 __choose_ai_action(self, ai: ArtificialIntelligence, time_to_react: int) -> Action: return_value = multiprocessing.Value('i', Action.get_default().get_index()) process = multiprocessing.Process(target=Controller.call_ai, args=(ai, self._game.copy(), return_value,)) start = datetime.now(time_zone) process.start() process.join(time_to_react - 1) # wait time_to_react seconds minus one for the calculation to be finished if process.is_alive(): # If an execution is terminated, the execution time is set to 1 minute. start = datetime.now(time_zone) - timedelta(seconds=60) process.terminate() self._log_execution_time(ai, (datetime.now(time_zone) - start).total_seconds()) return Action.get_by_index(return_value.value)
def read_next_action(self) -> Action: # noqa: C901 """See base class.""" while True: for event in self.__pygame.event.get(): if event.type == self.__pygame.QUIT: # Allows to close the pygame-window self.end() return Action.get_default() elif event.type == self.__pygame.KEYDOWN: pressed_key = self.__pygame.key.get_pressed() self.__next_action = False if pressed_key[self.__pygame.K_UP]: return Action.speed_up elif pressed_key[self.__pygame.K_DOWN]: return Action.slow_down elif pressed_key[self.__pygame.K_RIGHT]: return Action.turn_right elif pressed_key[self.__pygame.K_LEFT]: return Action.turn_left elif pressed_key[self.__pygame.K_SPACE]: return Action.change_nothing elif event.type == self.__pygame.KEYUP: self.__next_action = True