[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# Windows\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Daniel Slater\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# PyGamePlayer\nModule to help with running learning agents against PyGame games. Hooks into the PyGame screen update and event.get methods so you can run PyGame games with zero touches to the underlying game file. Can even deal with games with no main() method.\n\nProject contains three examples of running this, 2 a minimal examles one with Pong and one with Tetris and a full example of Deep-Q learning against Pong with tensorflow.\n\nMore information available here http://www.danielslater.net/2015/12/how-to-run-learning-agents-against.html\n\nRequirements\n----------\n- python 2 or 3\n- pygame\n- numpy\n\nGetting started\n-----------\nPyGame is probably the best supported library for games in Python it can be downloaded and installed from http://www.pygame.org/download.shtml\n\n[Numpy](http://www.scipy.org/scipylib/download.html) is also required\n\nCreate a Python 2 or 3 environment with both of these in it.\n\nImport this project and whatever PyGame game you want to train against into your working area. A bunch of PyGame games can be found here http://www.pygame.org/projects/6 or alternatly just use Pong or Tetris that are included with this project.\n\n[exmples/deep_q_pong_player.py](https://github.com/DanielSlater/PyGamePlayer/blob/master/examples/deep_q_pong_player.py) also requires that [tensorflow](https://www.tensorflow.org/versions/r0.8/get_started/os_setup.html) and [matplotlib](http://matplotlib.org/users/installing.html) be installed\n\nExample usage for Pong game\n-----------\n```\nfrom pygame_player import PyGamePlayer\n\n\nclass PongPlayer(PyGamePlayer):\n    def __init__(self):\n        super(PongPlayer, self).__init__(force_game_fps=10) \n        # force_game_fps fixes the game clock so that no matter how many real seconds it takes to run a fame \n        # the game behaves as if each frame took the same amount of time\n        # use run_real_time so the game will actually play at the force_game_fps frame rate\n        \n        self.last_bar1_score = 0.0\n        self.last_bar2_score = 0.0\n\n    def get_keys_pressed(self, screen_array, feedback):\n        # TODO: put an actual learning agent here\n        from pygame.constants import K_DOWN\n        return [K_DOWN] # just returns the down key\n\n    def get_feedback(self):\n        # import must be done here because otherwise importing would cause the game to start playing\n        from games.pong import bar1_score, bar2_score\n\n        # get the difference in score between this and the last run\n        score_change = (bar1_score - self.last_bar1_score) - (bar2_score - self.last_bar2_score)\n        self.last_bar1_score = bar1_score\n        self.last_bar2_score = bar2_score\n\n        return score_change\n\n\nif __name__ == '__main__':\n    player = PongPlayer()\n    player.start()\n```\n\nGames\n--------\n- [Pong](https://github.com/DanielSlater/PyGamePlayer/blob/master/games/pong.py)\n- [Tetris](https://github.com/DanielSlater/PyGamePlayer/blob/master/games/tetris.py)\n- [Mini Pong](https://github.com/DanielSlater/PyGamePlayer/blob/master/games/mini_pong.py) - modified version of pong to run in lower resolutions\n- [Half Pong](https://github.com/DanielSlater/PyGamePlayer/blob/master/games/half_pong.py) - simplified version of pong with just one bar "
  },
  {
    "path": "__init__.py",
    "content": "__author__ = 'Daniel'\n"
  },
  {
    "path": "examples/__init__.py",
    "content": "__author__ = 'Daniel'\n"
  },
  {
    "path": "examples/deep_q_half_pong_networks_40x40_6/checkpoint",
    "content": "model_checkpoint_path: \"network-1230000\"\nall_model_checkpoint_paths: \"network-1190000\"\nall_model_checkpoint_paths: \"network-1200000\"\nall_model_checkpoint_paths: \"network-1210000\"\nall_model_checkpoint_paths: \"network-1220000\"\nall_model_checkpoint_paths: \"network-1230000\"\n"
  },
  {
    "path": "examples/deep_q_half_pong_networks_40x40_8/checkpoint",
    "content": "model_checkpoint_path: \"network-1300000\"\nall_model_checkpoint_paths: \"network-1260000\"\nall_model_checkpoint_paths: \"network-1270000\"\nall_model_checkpoint_paths: \"network-1280000\"\nall_model_checkpoint_paths: \"network-1290000\"\nall_model_checkpoint_paths: \"network-1300000\"\n"
  },
  {
    "path": "examples/deep_q_half_pong_player.py",
    "content": "# This is heavily based off https://github.com/asrivat1/DeepLearningVideoGames\n# deep q learning agent that runs against Half-Pong. Runs on a much smaller screen and with fewer layers.\n# Performs significantly above random, but still has someway to go to match google deep mind performance...\n# To see a trained version of this network start it with the kwargs checkpoint_path=\"deep_q_half_pong_networks_40x40_8\"\n# and playback_mode=\"True\"\n\nimport os\nimport random\nfrom collections import deque\n\nimport tensorflow as tf\nimport numpy as np\nimport cv2\nfrom pygame.constants import K_DOWN, K_UP\n\nfrom pygame_player import PyGamePlayer\n\n\nclass DeepQHalfPongPlayer(PyGamePlayer):\n    ACTIONS_COUNT = 3  # number of valid actions. In this case up, still and down\n    FUTURE_REWARD_DISCOUNT = 0.99  # decay rate of past observations\n    OBSERVATION_STEPS = 50000.  # time steps to observe before training\n    EXPLORE_STEPS = 500000.  # frames over which to anneal epsilon\n    INITIAL_RANDOM_ACTION_PROB = 1.0  # starting chance of an action being random\n    FINAL_RANDOM_ACTION_PROB = 0.05  # final chance of an action being random\n    MEMORY_SIZE = 500000  # number of observations to remember\n    MINI_BATCH_SIZE = 200  # size of mini batches\n    STATE_FRAMES = 4  # number of frames to store in the state\n    OBS_LAST_STATE_INDEX, OBS_ACTION_INDEX, OBS_REWARD_INDEX, OBS_CURRENT_STATE_INDEX, OBS_TERMINAL_INDEX = range(5)\n    SAVE_EVERY_X_STEPS = 10000\n    LEARN_RATE = 1e-6\n    STORE_SCORES_LEN = 200.\n    SCREEN_WIDTH = 40\n    SCREEN_HEIGHT = 40\n\n    def __init__(self,\n                 # to see a trained network change checkpoint_path=\"deep_q_half_pong_networks_40x40_8\" and\n                 # playback_mode=\"True\"\n                 checkpoint_path=\"deep_q_half_pong_networks\",\n                 playback_mode=True,\n                 verbose_logging=True):\n        \"\"\"\n        Example of deep q network for pong\n\n        :param checkpoint_path: directory to store checkpoints in\n        :type checkpoint_path: str\n        :param playback_mode: if true games runs in real time mode and demos itself running\n        :type playback_mode: bool\n        :param verbose_logging: If true then extra log information is printed to std out\n        :type verbose_logging: bool\n        \"\"\"\n        self._playback_mode = playback_mode\n        self.last_score = 0\n        super(DeepQHalfPongPlayer, self).__init__(force_game_fps=8, run_real_time=playback_mode)\n        self.verbose_logging = verbose_logging\n        self._checkpoint_path = checkpoint_path\n        self._session = tf.Session()\n        self._input_layer, self._output_layer = self._create_network()\n\n        self._action = tf.placeholder(\"float\", [None, self.ACTIONS_COUNT])\n        self._target = tf.placeholder(\"float\", [None])\n\n        readout_action = tf.reduce_sum(tf.mul(self._output_layer, self._action), reduction_indices=1)\n\n        cost = tf.reduce_mean(tf.square(self._target - readout_action))\n        self._train_operation = tf.train.AdamOptimizer(self.LEARN_RATE).minimize(cost)\n\n        self._observations = deque()\n        self._last_scores = deque()\n\n        # set the first action to do nothing\n        self._last_action = np.zeros(self.ACTIONS_COUNT)\n        self._last_action[1] = 1\n\n        self._last_state = None\n        self._probability_of_random_action = self.INITIAL_RANDOM_ACTION_PROB\n        self._time = 0\n\n        self._session.run(tf.initialize_all_variables())\n\n        if not os.path.exists(self._checkpoint_path):\n            os.mkdir(self._checkpoint_path)\n        self._saver = tf.train.Saver()\n        checkpoint = tf.train.get_checkpoint_state(self._checkpoint_path)\n\n        if checkpoint and checkpoint.model_checkpoint_path:\n            self._saver.restore(self._session, checkpoint.model_checkpoint_path)\n            print(\"Loaded checkpoints %s\" % checkpoint.model_checkpoint_path)\n        elif playback_mode:\n            raise Exception(\"Could not load checkpoints for playback\")\n\n    def get_keys_pressed(self, screen_array, reward, terminal):\n        # images will be black or white\n        _, screen_binary = cv2.threshold(cv2.cvtColor(screen_array, cv2.COLOR_BGR2GRAY), 1, 255,\n                                         cv2.THRESH_BINARY)\n\n        if reward != 0.0:\n            self._last_scores.append(reward)\n            if len(self._last_scores) > self.STORE_SCORES_LEN:\n                self._last_scores.popleft()\n\n        # first frame must be handled differently\n        if self._last_state is None:\n            # the _last_state will contain the image data from the last self.STATE_FRAMES frames\n            self._last_state = np.stack(tuple(screen_binary for _ in range(self.STATE_FRAMES)), axis=2)\n            return DeepQHalfPongPlayer._key_presses_from_action(self._last_action)\n\n        screen_binary = np.reshape(screen_binary,\n                                   (self.SCREEN_WIDTH, self.SCREEN_HEIGHT, 1))\n        current_state = np.append(self._last_state[:, :, 1:], screen_binary, axis=2)\n\n        if not self._playback_mode:\n            # store the transition in previous_observations\n            self._observations.append((self._last_state, self._last_action, reward, current_state, terminal))\n\n            if len(self._observations) > self.MEMORY_SIZE:\n                self._observations.popleft()\n\n            # only train if done observing\n            if len(self._observations) > self.OBSERVATION_STEPS:\n                self._train()\n                self._time += 1\n\n        # update the old values\n        self._last_state = current_state\n\n        self._last_action = self._choose_next_action()\n\n        if not self._playback_mode:\n            # gradually reduce the probability of a random actionself.\n            if self._probability_of_random_action > self.FINAL_RANDOM_ACTION_PROB \\\n                    and len(self._observations) > self.OBSERVATION_STEPS:\n                self._probability_of_random_action -= \\\n                    (self.INITIAL_RANDOM_ACTION_PROB - self.FINAL_RANDOM_ACTION_PROB) / self.EXPLORE_STEPS\n\n            print(\"Time: %s random_action_prob: %s reward %s scores differential %s\" %\n                  (self._time, self._probability_of_random_action, reward,\n                   sum(self._last_scores) / self.STORE_SCORES_LEN))\n\n        return DeepQHalfPongPlayer._key_presses_from_action(self._last_action)\n\n    def _choose_next_action(self):\n        new_action = np.zeros([self.ACTIONS_COUNT])\n\n        if (not self._playback_mode) and (random.random() <= self._probability_of_random_action):\n            # choose an action randomly\n            action_index = random.randrange(self.ACTIONS_COUNT)\n        else:\n            # choose an action given our last state\n            readout_t = self._session.run(self._output_layer, feed_dict={self._input_layer: [self._last_state]})[0]\n            if self.verbose_logging:\n                print(\"Action Q-Values are %s\" % readout_t)\n            action_index = np.argmax(readout_t)\n\n        new_action[action_index] = 1\n        return new_action\n\n    def _train(self):\n        # sample a mini_batch to train on\n        mini_batch = random.sample(self._observations, self.MINI_BATCH_SIZE)\n        # get the batch variables\n        previous_states = [d[self.OBS_LAST_STATE_INDEX] for d in mini_batch]\n        actions = [d[self.OBS_ACTION_INDEX] for d in mini_batch]\n        rewards = [d[self.OBS_REWARD_INDEX] for d in mini_batch]\n        current_states = [d[self.OBS_CURRENT_STATE_INDEX] for d in mini_batch]\n        agents_expected_reward = []\n        # this gives us the agents expected reward for each action we might take\n        agents_reward_per_action = self._session.run(self._output_layer, feed_dict={self._input_layer: current_states})\n        for i in range(len(mini_batch)):\n            if mini_batch[i][self.OBS_TERMINAL_INDEX]:\n                # this was a terminal frame so there is no future reward...\n                agents_expected_reward.append(rewards[i])\n            else:\n                agents_expected_reward.append(\n                    rewards[i] + self.FUTURE_REWARD_DISCOUNT * np.max(agents_reward_per_action[i]))\n\n        # learn that these actions in these states lead to this reward\n        self._session.run(self._train_operation, feed_dict={\n            self._input_layer: previous_states,\n            self._action: actions,\n            self._target: agents_expected_reward})\n\n        # save checkpoints for later\n        if self._time % self.SAVE_EVERY_X_STEPS == 0:\n            self._saver.save(self._session, self._checkpoint_path + '/network', global_step=self._time)\n\n    def _create_network(self):\n        # network weights\n        convolution_weights_1 = tf.Variable(tf.truncated_normal([8, 8, self.STATE_FRAMES, 32], stddev=0.01))\n        convolution_bias_1 = tf.Variable(tf.constant(0.01, shape=[32]))\n\n        convolution_weights_2 = tf.Variable(tf.truncated_normal([4, 4, 32, 64], stddev=0.01))\n        convolution_bias_2 = tf.Variable(tf.constant(0.01, shape=[64]))\n\n        feed_forward_weights_1 = tf.Variable(tf.truncated_normal([256, 256], stddev=0.01))\n        feed_forward_bias_1 = tf.Variable(tf.constant(0.01, shape=[256]))\n\n        feed_forward_weights_2 = tf.Variable(tf.truncated_normal([256, self.ACTIONS_COUNT], stddev=0.01))\n        feed_forward_bias_2 = tf.Variable(tf.constant(0.01, shape=[self.ACTIONS_COUNT]))\n\n        input_layer = tf.placeholder(\"float\", [None, self.SCREEN_WIDTH, self.SCREEN_HEIGHT,\n                                               self.STATE_FRAMES])\n\n        hidden_convolutional_layer_1 = tf.nn.relu(\n            tf.nn.conv2d(input_layer, convolution_weights_1, strides=[1, 4, 4, 1], padding=\"SAME\") + convolution_bias_1)\n\n        hidden_max_pooling_layer_1 = tf.nn.max_pool(hidden_convolutional_layer_1, ksize=[1, 2, 2, 1],\n                                                    strides=[1, 2, 2, 1], padding=\"SAME\")\n\n        hidden_convolutional_layer_2 = tf.nn.relu(\n            tf.nn.conv2d(hidden_max_pooling_layer_1, convolution_weights_2, strides=[1, 2, 2, 1],\n                         padding=\"SAME\") + convolution_bias_2)\n\n        hidden_max_pooling_layer_2 = tf.nn.max_pool(hidden_convolutional_layer_2, ksize=[1, 2, 2, 1],\n                                                    strides=[1, 2, 2, 1], padding=\"SAME\")\n\n        hidden_convolutional_layer_3_flat = tf.reshape(hidden_max_pooling_layer_2, [-1, 256])\n\n        final_hidden_activations = tf.nn.relu(\n            tf.matmul(hidden_convolutional_layer_3_flat, feed_forward_weights_1) + feed_forward_bias_1)\n\n        output_layer = tf.matmul(final_hidden_activations, feed_forward_weights_2) + feed_forward_bias_2\n\n        return input_layer, output_layer\n\n    @staticmethod\n    def _key_presses_from_action(action_set):\n        if action_set[0] == 1:\n            return [K_DOWN]\n        elif action_set[1] == 1:\n            return []\n        elif action_set[2] == 1:\n            return [K_UP]\n        raise Exception(\"Unexpected action\")\n\n    def get_feedback(self):\n        from games.half_pong import score\n\n        # get the difference in score between this and the last run\n        score_change = (score - self.last_score)\n        self.last_score = score\n\n        return float(score_change), score_change == -1\n\n    def start(self):\n        super(DeepQHalfPongPlayer, self).start()\n\n        from games.half_pong import run\n        run(screen_width=self.SCREEN_WIDTH, screen_height=self.SCREEN_HEIGHT)\n\n\nif __name__ == '__main__':\n    # to see a trained network add the args checkpoint_path=\"deep_q_half_pong_networks_40x40_8\" and\n    # playback_mode=\"True\"\n    player = DeepQHalfPongPlayer()\n    player.start()\n"
  },
  {
    "path": "examples/deep_q_pong_player.py",
    "content": "# This is heavily based off https://github.com/asrivat1/DeepLearningVideoGames\nimport os\nimport random\nfrom collections import deque\nfrom pong_player import PongPlayer\nimport tensorflow as tf\nimport numpy as np\nimport cv2\nfrom pygame.constants import K_DOWN, K_UP\n\n\nclass DeepQPongPlayer(PongPlayer):\n    ACTIONS_COUNT = 3  # number of valid actions. In this case up, still and down\n    FUTURE_REWARD_DISCOUNT = 0.99  # decay rate of past observations\n    OBSERVATION_STEPS = 50000.  # time steps to observe before training\n    EXPLORE_STEPS = 500000.  # frames over which to anneal epsilon\n    INITIAL_RANDOM_ACTION_PROB = 1.0  # starting chance of an action being random\n    FINAL_RANDOM_ACTION_PROB = 0.05  # final chance of an action being random\n    MEMORY_SIZE = 500000  # number of observations to remember\n    MINI_BATCH_SIZE = 100  # size of mini batches\n    STATE_FRAMES = 4  # number of frames to store in the state\n    RESIZED_SCREEN_X, RESIZED_SCREEN_Y = (80, 80)\n    OBS_LAST_STATE_INDEX, OBS_ACTION_INDEX, OBS_REWARD_INDEX, OBS_CURRENT_STATE_INDEX, OBS_TERMINAL_INDEX = range(5)\n    SAVE_EVERY_X_STEPS = 10000\n    LEARN_RATE = 1e-6\n    STORE_SCORES_LEN = 200.\n\n    def __init__(self, checkpoint_path=\"deep_q_pong_networks\", playback_mode=False, verbose_logging=False):\n        \"\"\"\n        Example of deep q network for pong\n\n        :param checkpoint_path: directory to store checkpoints in\n        :type checkpoint_path: str\n        :param playback_mode: if true games runs in real time mode and demos itself running\n        :type playback_mode: bool\n        :param verbose_logging: If true then extra log information is printed to std out\n        :type verbose_logging: bool\n        \"\"\"\n        self._playback_mode = playback_mode\n        super(DeepQPongPlayer, self).__init__(force_game_fps=8, run_real_time=playback_mode)\n        self.verbose_logging = verbose_logging\n        self._checkpoint_path = checkpoint_path\n        self._session = tf.Session()\n        self._input_layer, self._output_layer = DeepQPongPlayer._create_network()\n\n        self._action = tf.placeholder(\"float\", [None, self.ACTIONS_COUNT])\n        self._target = tf.placeholder(\"float\", [None])\n\n        readout_action = tf.reduce_sum(tf.mul(self._output_layer, self._action), reduction_indices=1)\n\n        cost = tf.reduce_mean(tf.square(self._target - readout_action))\n        self._train_operation = tf.train.AdamOptimizer(self.LEARN_RATE).minimize(cost)\n\n        self._observations = deque()\n        self._last_scores = deque()\n\n        # set the first action to do nothing\n        self._last_action = np.zeros(self.ACTIONS_COUNT)\n        self._last_action[1] = 1\n\n        self._last_state = None\n        self._probability_of_random_action = self.INITIAL_RANDOM_ACTION_PROB\n        self._time = 0\n\n        self._session.run(tf.initialize_all_variables())\n\n        if not os.path.exists(self._checkpoint_path):\n            os.mkdir(self._checkpoint_path)\n        self._saver = tf.train.Saver()\n        checkpoint = tf.train.get_checkpoint_state(self._checkpoint_path)\n\n        if checkpoint and checkpoint.model_checkpoint_path:\n            self._saver.restore(self._session, checkpoint.model_checkpoint_path)\n            print(\"Loaded checkpoints %s\" % checkpoint.model_checkpoint_path)\n        elif playback_mode:\n            raise Exception(\"Could not load checkpoints for playback\")\n\n    def get_keys_pressed(self, screen_array, reward, terminal):\n        # scale down screen image\n        screen_resized_grayscaled = cv2.cvtColor(cv2.resize(screen_array,\n                                                            (self.RESIZED_SCREEN_X, self.RESIZED_SCREEN_Y)),\n                                                 cv2.COLOR_BGR2GRAY)\n\n        # set the pixels to all be 0. or 1.\n        _, screen_resized_binary = cv2.threshold(screen_resized_grayscaled, 1, 255, cv2.THRESH_BINARY)\n\n        if reward != 0.0:\n            self._last_scores.append(reward)\n            if len(self._last_scores) > self.STORE_SCORES_LEN:\n                self._last_scores.popleft()\n\n        # first frame must be handled differently\n        if self._last_state is None:\n            # the _last_state will contain the image data from the last self.STATE_FRAMES frames\n            self._last_state = np.stack(tuple(screen_resized_binary for _ in range(self.STATE_FRAMES)), axis=2)\n            return DeepQPongPlayer._key_presses_from_action(self._last_action)\n\n        screen_resized_binary = np.reshape(screen_resized_binary,\n                                               (self.RESIZED_SCREEN_X, self.RESIZED_SCREEN_Y, 1))\n        current_state = np.append(self._last_state[:, :, 1:], screen_resized_binary, axis=2)\n\n        if not self._playback_mode:\n            # store the transition in previous_observations\n            self._observations.append((self._last_state, self._last_action, reward, current_state, terminal))\n\n            if len(self._observations) > self.MEMORY_SIZE:\n                self._observations.popleft()\n\n            # only train if done observing\n            if len(self._observations) > self.OBSERVATION_STEPS:\n                self._train()\n                self._time += 1\n\n        # update the old values\n        self._last_state = current_state\n\n        self._last_action = self._choose_next_action()\n\n        if not self._playback_mode:\n            # gradually reduce the probability of a random actionself.\n            if self._probability_of_random_action > self.FINAL_RANDOM_ACTION_PROB \\\n                    and len(self._observations) > self.OBSERVATION_STEPS:\n                self._probability_of_random_action -= \\\n                    (self.INITIAL_RANDOM_ACTION_PROB - self.FINAL_RANDOM_ACTION_PROB) / self.EXPLORE_STEPS\n\n            print(\"Time: %s random_action_prob: %s reward %s scores differential %s\" %\n                  (self._time, self._probability_of_random_action, reward,\n                   sum(self._last_scores) / self.STORE_SCORES_LEN))\n\n        return DeepQPongPlayer._key_presses_from_action(self._last_action)\n\n    def _choose_next_action(self):\n        new_action = np.zeros([self.ACTIONS_COUNT])\n\n        if (not self._playback_mode) and (random.random() <= self._probability_of_random_action):\n            # choose an action randomly\n            action_index = random.randrange(self.ACTIONS_COUNT)\n        else:\n            # choose an action given our last state\n            readout_t = self._session.run(self._output_layer, feed_dict={self._input_layer: [self._last_state]})[0]\n            if self.verbose_logging:\n                print(\"Action Q-Values are %s\" % readout_t)\n            action_index = np.argmax(readout_t)\n\n        new_action[action_index] = 1\n        return new_action\n\n    def _train(self):\n        # sample a mini_batch to train on\n        mini_batch = random.sample(self._observations, self.MINI_BATCH_SIZE)\n        # get the batch variables\n        previous_states = [d[self.OBS_LAST_STATE_INDEX] for d in mini_batch]\n        actions = [d[self.OBS_ACTION_INDEX] for d in mini_batch]\n        rewards = [d[self.OBS_REWARD_INDEX] for d in mini_batch]\n        current_states = [d[self.OBS_CURRENT_STATE_INDEX] for d in mini_batch]\n        agents_expected_reward = []\n        # this gives us the agents expected reward for each action we might\n        agents_reward_per_action = self._session.run(self._output_layer, feed_dict={self._input_layer: current_states})\n        for i in range(len(mini_batch)):\n            if mini_batch[i][self.OBS_TERMINAL_INDEX]:\n                # this was a terminal frame so there is no future reward...\n                agents_expected_reward.append(rewards[i])\n            else:\n                agents_expected_reward.append(\n                    rewards[i] + self.FUTURE_REWARD_DISCOUNT * np.max(agents_reward_per_action[i]))\n\n        # learn that these actions in these states lead to this reward\n        self._session.run(self._train_operation, feed_dict={\n            self._input_layer: previous_states,\n            self._action: actions,\n            self._target: agents_expected_reward})\n\n        # save checkpoints for later\n        if self._time % self.SAVE_EVERY_X_STEPS == 0:\n            self._saver.save(self._session, self._checkpoint_path + '/network', global_step=self._time)\n\n    @staticmethod\n    def _create_network():\n        # network weights\n        convolution_weights_1 = tf.Variable(tf.truncated_normal([8, 8, DeepQPongPlayer.STATE_FRAMES, 32], stddev=0.01))\n        convolution_bias_1 = tf.Variable(tf.constant(0.01, shape=[32]))\n\n        convolution_weights_2 = tf.Variable(tf.truncated_normal([4, 4, 32, 64], stddev=0.01))\n        convolution_bias_2 = tf.Variable(tf.constant(0.01, shape=[64]))\n\n        convolution_weights_3 = tf.Variable(tf.truncated_normal([3, 3, 64, 64], stddev=0.01))\n        convolution_bias_3 = tf.Variable(tf.constant(0.01, shape=[64]))\n\n        feed_forward_weights_1 = tf.Variable(tf.truncated_normal([256, 256], stddev=0.01))\n        feed_forward_bias_1 = tf.Variable(tf.constant(0.01, shape=[256]))\n\n        feed_forward_weights_2 = tf.Variable(tf.truncated_normal([256, DeepQPongPlayer.ACTIONS_COUNT], stddev=0.01))\n        feed_forward_bias_2 = tf.Variable(tf.constant(0.01, shape=[DeepQPongPlayer.ACTIONS_COUNT]))\n\n        input_layer = tf.placeholder(\"float\", [None, DeepQPongPlayer.RESIZED_SCREEN_X, DeepQPongPlayer.RESIZED_SCREEN_Y,\n                                               DeepQPongPlayer.STATE_FRAMES])\n\n        hidden_convolutional_layer_1 = tf.nn.relu(\n            tf.nn.conv2d(input_layer, convolution_weights_1, strides=[1, 4, 4, 1], padding=\"SAME\") + convolution_bias_1)\n\n        hidden_max_pooling_layer_1 = tf.nn.max_pool(hidden_convolutional_layer_1, ksize=[1, 2, 2, 1],\n                                                    strides=[1, 2, 2, 1], padding=\"SAME\")\n\n        hidden_convolutional_layer_2 = tf.nn.relu(\n            tf.nn.conv2d(hidden_max_pooling_layer_1, convolution_weights_2, strides=[1, 2, 2, 1],\n                         padding=\"SAME\") + convolution_bias_2)\n\n        hidden_max_pooling_layer_2 = tf.nn.max_pool(hidden_convolutional_layer_2, ksize=[1, 2, 2, 1],\n                                                    strides=[1, 2, 2, 1], padding=\"SAME\")\n\n        hidden_convolutional_layer_3 = tf.nn.relu(\n            tf.nn.conv2d(hidden_max_pooling_layer_2, convolution_weights_3,\n                         strides=[1, 1, 1, 1], padding=\"SAME\") + convolution_bias_3)\n\n        hidden_max_pooling_layer_3 = tf.nn.max_pool(hidden_convolutional_layer_3, ksize=[1, 2, 2, 1],\n                                                    strides=[1, 2, 2, 1], padding=\"SAME\")\n\n        hidden_convolutional_layer_3_flat = tf.reshape(hidden_max_pooling_layer_3, [-1, 256])\n\n        final_hidden_activations = tf.nn.relu(\n            tf.matmul(hidden_convolutional_layer_3_flat, feed_forward_weights_1) + feed_forward_bias_1)\n\n        output_layer = tf.matmul(final_hidden_activations, feed_forward_weights_2) + feed_forward_bias_2\n\n        return input_layer, output_layer\n\n    @staticmethod\n    def _key_presses_from_action(action_set):\n        if action_set[0] == 1:\n            return [K_DOWN]\n        elif action_set[1] == 1:\n            return []\n        elif action_set[2] == 1:\n            return [K_UP]\n        raise Exception(\"Unexpected action\")\n\n\nif __name__ == '__main__':\n    player = DeepQPongPlayer()\n    player.start()\n"
  },
  {
    "path": "examples/pong_player.py",
    "content": "from pygame.constants import K_DOWN\nfrom pygame_player import PyGamePlayer\n\n\nclass PongPlayer(PyGamePlayer):\n    def __init__(self, force_game_fps=10, run_real_time=False):\n        \"\"\"\n        Example class for playing Pong\n        \"\"\"\n        super(PongPlayer, self).__init__(force_game_fps=force_game_fps, run_real_time=run_real_time)\n        self.last_bar1_score = 0.0\n        self.last_bar2_score = 0.0\n\n    def get_keys_pressed(self, screen_array, feedback, terminal):\n        # TODO: put an actual learning agent here\n        return [K_DOWN]\n\n    def get_feedback(self):\n        # import must be done here because otherwise importing would cause the game to start playing\n        from games.pong import bar1_score, bar2_score\n\n        # get the difference in score between this and the last run\n        score_change = (bar1_score - self.last_bar1_score) - (bar2_score - self.last_bar2_score)\n        self.last_bar1_score = bar1_score\n        self.last_bar2_score = bar2_score\n\n        return float(score_change), score_change != 0\n\n    def start(self):\n        super(PongPlayer, self).start()\n\n        import games.pong\n\n\nif __name__ == '__main__':\n    player = PongPlayer()\n    player.start()"
  },
  {
    "path": "examples/tetris_player.py",
    "content": "from pygame.constants import K_LEFT\nfrom pygame_player import PyGamePlayer, function_intercept\nimport games.tetris\n\n\nclass TetrisPlayer(PyGamePlayer):\n    def __init__(self):\n        \"\"\"\n        Example class for playing Tetris\n        \"\"\"\n        super(TetrisPlayer, self).__init__(force_game_fps=5)\n        self._toggle_down_key = True\n        self._new_reward = 0.0\n        self._terminal = False\n\n        def add_removed_lines_to_reward(lines_removed, *args, **kwargs):\n            self._new_reward += lines_removed\n            return lines_removed\n\n        def check_for_game_over(ret, text):\n            if text == 'Game Over':\n                self._terminal = True\n\n        # to get the reward we will intercept the removeCompleteLines method and store what it returns\n        games.tetris.removeCompleteLines = function_intercept(games.tetris.removeCompleteLines,\n                                                              add_removed_lines_to_reward)\n        # find out if we have had a game over\n        games.tetris.showTextScreen = function_intercept(games.tetris.showTextScreen,\n                                                         check_for_game_over)\n\n    def get_keys_pressed(self, screen_array, feedback, terminal):\n        # TODO: put an actual learning agent here\n        # toggle key presses so we get through the start menu\n\n        if self._toggle_down_key:\n            self._toggle_down_key = False\n            return [K_LEFT]\n        else:\n            self._toggle_down_key = True\n            return []\n\n    def get_feedback(self):\n        temp = self._new_reward\n        self._new_reward = 0.0\n        terminal = self._terminal\n        self._terminal = False\n        return temp, terminal\n\n    def start(self):\n        super(TetrisPlayer, self).start()\n\n        games.tetris.main()\n\nif __name__ == '__main__':\n    player = TetrisPlayer()\n    player.start()\n"
  },
  {
    "path": "games/__init__.py",
    "content": "__author__ = 'Daniel'\n"
  },
  {
    "path": "games/half_pong.py",
    "content": "# Modified from http://www.pygame.org/project-Very+simple+Pong+game-816-.html\nimport pygame\nfrom pygame.locals import *\n\nscore = 0\n\n\ndef run(screen_width=40., screen_height=40.):\n    global score\n    pygame.init()\n\n    bar_width, bar_height = screen_width / 32., screen_height / 6.\n    bar_dist_from_edge = screen_width / 64.\n    circle_diameter = screen_height / 16.\n    circle_radius = circle_diameter / 2.\n    bar_1_start_x = bar_dist_from_edge\n    bar_start_y = (screen_height - bar_height) / 2.\n    bar_max_y = screen_height - bar_height - bar_dist_from_edge\n    circle_start_x, circle_start_y = (screen_width - circle_diameter), (screen_width - circle_diameter) / 2.\n\n    screen = pygame.display.set_mode((int(screen_width), int(screen_height)), 0, 32)\n\n    # Creating 2 bars, a ball and background.\n    back = pygame.Surface((int(screen_width), int(screen_height)))\n    background = back.convert()\n    background.fill((0, 0, 0))\n    bar = pygame.Surface((int(bar_width), int(bar_height)))\n    bar1 = bar.convert()\n    bar1.fill((255, 255, 255))\n    circle_surface = pygame.Surface((int(circle_diameter), int(circle_diameter)))\n    pygame.draw.circle(circle_surface, (255, 255, 255), (int(circle_radius), int(circle_radius)), int(circle_radius))\n    circle = circle_surface.convert()\n    circle.set_colorkey((0, 0, 0))\n\n    # some definitions\n    bar1_x = bar_1_start_x\n    bar1_y = bar_start_y\n    circle_x, circle_y = circle_start_x, circle_start_y\n    bar1_move, bar2_move = 0., 0.\n    speed_x, speed_y, speed_bar = -screen_width / 1.28, screen_height / 1.92, screen_height * 1.2\n\n    clock = pygame.time.Clock()\n\n    done = False\n    while not done:\n        for event in pygame.event.get():  # User did something\n            if event.type == pygame.QUIT:  # If user clicked close\n                done = True  # Flag that we are done so we exit this loop\n            if event.type == KEYDOWN:\n                if event.key == K_UP:\n                    bar1_move = -ai_speed\n                elif event.key == K_DOWN:\n                    bar1_move = ai_speed\n            elif event.type == KEYUP:\n                if event.key == K_UP:\n                    bar1_move = 0.\n                elif event.key == K_DOWN:\n                    bar1_move = 0.\n\n        screen.blit(background, (0, 0))\n        screen.blit(bar1, (bar1_x, bar1_y))\n        screen.blit(circle, (circle_x, circle_y))\n\n        bar1_y += bar1_move\n\n        # movement of circle\n        time_passed = clock.tick(30)\n        time_sec = time_passed / 1000.0\n\n        circle_x += speed_x * time_sec\n        circle_y += speed_y * time_sec\n        ai_speed = speed_bar * time_sec\n\n        if bar1_y >= bar_max_y:\n            bar1_y = bar_max_y\n        elif bar1_y <= bar_dist_from_edge:\n            bar1_y = bar_dist_from_edge\n\n        if circle_x < bar_dist_from_edge + bar_width:\n            if circle_y >= bar1_y - circle_radius and circle_y <= bar1_y + bar_height + circle_radius:\n                circle_x = bar_dist_from_edge + bar_width\n                speed_x = -speed_x\n        if circle_x < -circle_radius:\n            score -= 1\n            circle_x, circle_y = circle_start_x, circle_start_y\n            bar1_y, bar_2_y = bar_start_y, bar_start_y\n        elif circle_x > screen_width - circle_diameter:\n            score += 1\n            speed_x = -speed_x\n        if circle_y <= bar_dist_from_edge:\n            speed_y = -speed_y\n            circle_y = bar_dist_from_edge\n        elif circle_y >= screen_height - circle_diameter - circle_radius:\n            speed_y = -speed_y\n            circle_y = screen_height - circle_diameter - circle_radius\n\n        pygame.display.update()\n\n    pygame.quit()\n\n\nif __name__ == '__main__':\n    run()\n"
  },
  {
    "path": "games/mini_pong.py",
    "content": "# Modified from http://www.pygame.org/project-Very+simple+Pong+game-816-.html\nimport pygame\nfrom pygame.locals import *\n\nbar1_score, bar2_score = 0, 0\n\n\ndef run(screen_width=40., screen_height=40.):\n    global bar1_score, bar2_score\n    pygame.init()\n\n    bar_width, bar_height = screen_width / 32., screen_height / 9.6\n    bar_dist_from_edge = screen_width / 64.\n    circle_diameter = screen_height / 16.\n    circle_radius = circle_diameter / 2.\n    bar_1_start_x, bar_2_start_x = bar_dist_from_edge, screen_width - bar_dist_from_edge - bar_width\n    bar_start_y = (screen_height - bar_height) / 2.\n    bar_max_y = screen_height - bar_height - bar_dist_from_edge\n    circle_start_x, circle_start_y = (screen_width - circle_diameter) / 2., (screen_width - circle_diameter) / 2.\n\n    screen = pygame.display.set_mode((int(screen_width), int(screen_height)), 0, 32)\n\n    # Creating 2 bars, a ball and background.\n    back = pygame.Surface((int(screen_width), int(screen_height)))\n    background = back.convert()\n    background.fill((0, 0, 0))\n    bar = pygame.Surface((int(bar_width), int(bar_height)))\n    bar1 = bar.convert()\n    bar1.fill((255, 255, 255))\n    bar2 = bar.convert()\n    bar2.fill((255, 255, 255))\n    circle_surface = pygame.Surface((int(circle_diameter), int(circle_diameter)))\n    pygame.draw.circle(circle_surface, (255, 255, 255), (int(circle_radius), int(circle_radius)), int(circle_radius))\n    circle = circle_surface.convert()\n    circle.set_colorkey((0, 0, 0))\n\n    # some definitions\n    bar1_x, bar2_x = bar_1_start_x, bar_2_start_x\n    bar1_y, bar2_y = bar_start_y, bar_start_y\n    circle_x, circle_y = circle_start_x, circle_start_y\n    bar1_move, bar2_move = 0., 0.\n    speed_x, speed_y, speed_circle = screen_width / 2.56, screen_height / 1.92, screen_width / 2.56  # 250., 250., 250.\n\n    clock = pygame.time.Clock()\n\n    done = False\n    while not done:\n        for event in pygame.event.get():  # User did something\n            if event.type == pygame.QUIT:  # If user clicked close\n                done = True  # Flag that we are done so we exit this loop\n            if event.type == KEYDOWN:\n                if event.key == K_UP:\n                    bar1_move = -ai_speed\n                elif event.key == K_DOWN:\n                    bar1_move = ai_speed\n            elif event.type == KEYUP:\n                if event.key == K_UP:\n                    bar1_move = 0.\n                elif event.key == K_DOWN:\n                    bar1_move = 0.\n\n        screen.blit(background, (0, 0))\n        screen.blit(bar1, (bar1_x, bar1_y))\n        screen.blit(bar2, (bar2_x, bar2_y))\n        screen.blit(circle, (circle_x, circle_y))\n\n        bar1_y += bar1_move\n\n        # movement of circle\n        time_passed = clock.tick(30)\n        time_sec = time_passed / 1000.0\n\n        circle_x += speed_x * time_sec\n        circle_y += speed_y * time_sec\n        ai_speed = speed_circle * time_sec\n\n        # AI of the computer.\n        if circle_x >= (screen_width / 2.) - circle_diameter:\n            if not bar2_y == circle_y + circle_radius:\n                if bar2_y < circle_y + circle_radius:\n                    bar2_y += ai_speed\n                if bar2_y > circle_y - (bar_height - circle_radius):\n                    bar2_y -= ai_speed\n            else:\n                bar2_y == circle_y + circle_radius\n\n        if bar1_y >= bar_max_y:\n            bar1_y = bar_max_y\n        elif bar1_y <= bar_dist_from_edge:\n            bar1_y = bar_dist_from_edge\n        if bar2_y >= bar_max_y:\n            bar2_y = bar_max_y\n        elif bar2_y <= bar_dist_from_edge:\n            bar2_y = bar_dist_from_edge\n        # since i don't know anything about collision, ball hitting bars goes like this.\n        if circle_x <= bar1_x + bar_dist_from_edge:\n            if circle_y >= bar1_y - circle_radius and circle_y <= bar1_y + (bar_height - circle_radius):\n                circle_x = bar_dist_from_edge + bar_width\n                speed_x = -speed_x\n        if circle_x >= bar2_x - circle_diameter:\n            if circle_y >= bar2_y - circle_radius and circle_y <= bar2_y + (bar_height - circle_radius):\n                circle_x = screen_width - bar_dist_from_edge - bar_width - circle_diameter\n                speed_x = -speed_x\n        if circle_x < -circle_radius:\n            bar2_score += 1\n            circle_x, circle_y = (screen_width + circle_diameter) / 2., circle_start_y\n            bar1_y, bar_2_y = bar_start_y, bar_start_y\n        elif circle_x > screen_width - circle_diameter:\n            bar1_score += 1\n            circle_x, circle_y = circle_start_x, circle_start_y\n            bar1_y, bar2_y = bar_start_y, bar_start_y\n        if circle_y <= bar_dist_from_edge:\n            speed_y = -speed_y\n            circle_y = bar_dist_from_edge\n        elif circle_y >= screen_height - circle_diameter - circle_radius:\n            speed_y = -speed_y\n            circle_y = screen_height - circle_diameter - circle_radius\n\n        pygame.display.update()\n\n    pygame.quit()\n\n\nif __name__ == '__main__':\n    run()\n"
  },
  {
    "path": "games/pong.py",
    "content": "#Modified from http://www.pygame.org/project-Very+simple+Pong+game-816-.html\n#       This program is free software; you can redistribute it and/or modify\n#       it under the terms of the GNU General Public License as published by\n#       the Free Software Foundation; either version 2 of the License, or\n#       (at your option) any later version.\n#\n#       This program is distributed in the hope that it will be useful,\n#       but WITHOUT ANY WARRANTY; without even the implied warranty of\n#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n#       GNU General Public License for more details.\nimport numpy\nimport pygame\nfrom pygame.locals import *\nfrom sys import exit\nimport random\nimport pygame.surfarray as surfarray\n\npygame.init()\n\nscreen = pygame.display.set_mode((640,480),0,32)\n\n#Creating 2 bars, a ball and background.\nback = pygame.Surface((640,480))\nbackground = back.convert()\nbackground.fill((0,0,0))\nbar = pygame.Surface((10,50))\nbar1 = bar.convert()\nbar1.fill((255,255,255))\nbar2 = bar.convert()\nbar2.fill((255,255,255))\ncirc_sur = pygame.Surface((15,15))\ncirc = pygame.draw.circle(circ_sur,(255,255,255),(int(15/2),int(15/2)),int(15/2))\ncircle = circ_sur.convert()\ncircle.set_colorkey((0,0,0))\n\n\n\n# some definitions\nbar1_x, bar2_x = 10. , 620.\nbar1_y, bar2_y = 215. , 215.\ncircle_x, circle_y = 307.5, 232.5\nbar1_move, bar2_move = 0. , 0.\nspeed_x, speed_y, speed_circ = 250., 250., 250.\nbar1_score, bar2_score = 0,0\n\n#clock and font objects\nclock = pygame.time.Clock()\nfont = pygame.font.SysFont(\"calibri\",40)\n\ndone = False\nwhile done==False:       \n    for event in pygame.event.get(): # User did something\n        if event.type == pygame.QUIT: # If user clicked close\n            done = True # Flag that we are done so we exit this loop\n        if event.type == KEYDOWN:\n            if event.key == K_UP:\n                bar1_move = -ai_speed\n            elif event.key == K_DOWN:\n                bar1_move = ai_speed\n        elif event.type == KEYUP:\n            if event.key == K_UP:\n                bar1_move = 0.\n            elif event.key == K_DOWN:\n                bar1_move = 0.\n            \n    score1 = font.render(str(bar1_score), True,(255,255,255))\n    score2 = font.render(str(bar2_score), True,(255,255,255))\n\n    screen.blit(background,(0,0))\n    frame = pygame.draw.rect(screen,(255,255,255),Rect((5,5),(630,470)),2)\n    middle_line = pygame.draw.aaline(screen,(255,255,255),(330,5),(330,475))\n    screen.blit(bar1,(bar1_x,bar1_y))\n    screen.blit(bar2,(bar2_x,bar2_y))\n    screen.blit(circle,(circle_x,circle_y))\n    screen.blit(score1,(250.,210.))\n    screen.blit(score2,(380.,210.))\n\n    bar1_y += bar1_move\n        \n    # movement of circle\n    time_passed = clock.tick(30)\n    time_sec = time_passed / 1000.0\n        \n    circle_x += speed_x * time_sec\n    circle_y += speed_y * time_sec\n    ai_speed = speed_circ * time_sec\n    \n    #AI of the computer.\n    if circle_x >= 305.:\n        if not bar2_y == circle_y + 7.5:\n            if bar2_y < circle_y + 7.5:\n                bar2_y += ai_speed\n            if  bar2_y > circle_y - 42.5:\n                bar2_y -= ai_speed\n        else:\n            bar2_y == circle_y + 7.5\n    \n    if bar1_y >= 420.: bar1_y = 420.\n    elif bar1_y <= 10. : bar1_y = 10.\n    if bar2_y >= 420.: bar2_y = 420.\n    elif bar2_y <= 10.: bar2_y = 10.\n    #since i don't know anything about collision, ball hitting bars goes like this.\n    if circle_x <= bar1_x + 10.:\n        if circle_y >= bar1_y - 7.5 and circle_y <= bar1_y + 42.5:\n            circle_x = 20.\n            speed_x = -speed_x\n    if circle_x >= bar2_x - 15.:\n        if circle_y >= bar2_y - 7.5 and circle_y <= bar2_y + 42.5:\n            circle_x = 605.\n            speed_x = -speed_x\n    if circle_x < 5.:\n        bar2_score += 1\n        circle_x, circle_y = 320., 232.5\n        bar1_y,bar_2_y = 215., 215.\n    elif circle_x > 620.:\n        bar1_score += 1\n        circle_x, circle_y = 307.5, 232.5\n        bar1_y, bar2_y = 215., 215.\n    if circle_y <= 10.:\n        speed_y = -speed_y\n        circle_y = 10.\n    elif circle_y >= 457.5:\n        speed_y = -speed_y\n        circle_y = 457.5\n\n    pygame.display.update()\n            \npygame.quit()\n\n"
  },
  {
    "path": "games/tetris.py",
    "content": "# Tetromino (a Tetris clone)\n# By Al Sweigart al@inventwithpython.com\n# http://inventwithpython.com/pygame\n# Released under a \"Simplified BSD\" license\n\nimport random, time, pygame, sys\nfrom pygame.locals import *\n\nFPS = 25\nWINDOWWIDTH = 640\nWINDOWHEIGHT = 480\nBOXSIZE = 20\nBOARDWIDTH = 10\nBOARDHEIGHT = 20\nBLANK = '.'\n\nMOVESIDEWAYSFREQ = 0.15\nMOVEDOWNFREQ = 0.1\n\nXMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)\nTOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5\n\n#               R    G    B\nWHITE       = (255, 255, 255)\nGRAY        = (185, 185, 185)\nBLACK       = (  0,   0,   0)\nRED         = (155,   0,   0)\nLIGHTRED    = (175,  20,  20)\nGREEN       = (  0, 155,   0)\nLIGHTGREEN  = ( 20, 175,  20)\nBLUE        = (  0,   0, 155)\nLIGHTBLUE   = ( 20,  20, 175)\nYELLOW      = (155, 155,   0)\nLIGHTYELLOW = (175, 175,  20)\n\nBORDERCOLOR = BLUE\nBGCOLOR = BLACK\nTEXTCOLOR = WHITE\nTEXTSHADOWCOLOR = GRAY\nCOLORS      = (     BLUE,      GREEN,      RED,      YELLOW)\nLIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)\nassert len(COLORS) == len(LIGHTCOLORS) # each color must have light color\n\nTEMPLATEWIDTH = 5\nTEMPLATEHEIGHT = 5\n\nS_SHAPE_TEMPLATE = [['.....',\n                     '.....',\n                     '..OO.',\n                     '.OO..',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '..OO.',\n                     '...O.',\n                     '.....']]\n\nZ_SHAPE_TEMPLATE = [['.....',\n                     '.....',\n                     '.OO..',\n                     '..OO.',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '.OO..',\n                     '.O...',\n                     '.....']]\n\nI_SHAPE_TEMPLATE = [['..O..',\n                     '..O..',\n                     '..O..',\n                     '..O..',\n                     '.....'],\n                    ['.....',\n                     '.....',\n                     'OOOO.',\n                     '.....',\n                     '.....']]\n\nO_SHAPE_TEMPLATE = [['.....',\n                     '.....',\n                     '.OO..',\n                     '.OO..',\n                     '.....']]\n\nJ_SHAPE_TEMPLATE = [['.....',\n                     '.O...',\n                     '.OOO.',\n                     '.....',\n                     '.....'],\n                    ['.....',\n                     '..OO.',\n                     '..O..',\n                     '..O..',\n                     '.....'],\n                    ['.....',\n                     '.....',\n                     '.OOO.',\n                     '...O.',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '..O..',\n                     '.OO..',\n                     '.....']]\n\nL_SHAPE_TEMPLATE = [['.....',\n                     '...O.',\n                     '.OOO.',\n                     '.....',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '..O..',\n                     '..OO.',\n                     '.....'],\n                    ['.....',\n                     '.....',\n                     '.OOO.',\n                     '.O...',\n                     '.....'],\n                    ['.....',\n                     '.OO..',\n                     '..O..',\n                     '..O..',\n                     '.....']]\n\nT_SHAPE_TEMPLATE = [['.....',\n                     '..O..',\n                     '.OOO.',\n                     '.....',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '..OO.',\n                     '..O..',\n                     '.....'],\n                    ['.....',\n                     '.....',\n                     '.OOO.',\n                     '..O..',\n                     '.....'],\n                    ['.....',\n                     '..O..',\n                     '.OO..',\n                     '..O..',\n                     '.....']]\n\nPIECES = {'S': S_SHAPE_TEMPLATE,\n          'Z': Z_SHAPE_TEMPLATE,\n          'J': J_SHAPE_TEMPLATE,\n          'L': L_SHAPE_TEMPLATE,\n          'I': I_SHAPE_TEMPLATE,\n          'O': O_SHAPE_TEMPLATE,\n          'T': T_SHAPE_TEMPLATE}\n\n\ndef main():\n    global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT\n    pygame.init()\n    FPSCLOCK = pygame.time.Clock()\n    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))\n    BASICFONT = pygame.font.Font('freesansbold.ttf', 18)\n    BIGFONT = pygame.font.Font('freesansbold.ttf', 100)\n    pygame.display.set_caption('Tetromino')\n\n    showTextScreen('Tetromino')\n    while True: # game loop\n        #if random.randint(0, 1) == 0:\n        #    pygame.mixer.music.load('tetrisb.mid')\n        #else:\n        #    pygame.mixer.music.load('tetrisc.mid')\n        #pygame.mixer.music.play(-1, 0.0)\n        runGame()\n        #pygame.mixer.music.stop()\n        showTextScreen('Game Over')\n\n\ndef runGame():\n    # setup variables for the start of the game\n    board = getBlankBoard()\n    lastMoveDownTime = time.time()\n    lastMoveSidewaysTime = time.time()\n    lastFallTime = time.time()\n    movingDown = False # note: there is no movingUp variable\n    movingLeft = False\n    movingRight = False\n    score = 0\n    level, fallFreq = calculateLevelAndFallFreq(score)\n\n    fallingPiece = getNewPiece()\n    nextPiece = getNewPiece()\n\n    while True: # game loop\n        if fallingPiece == None:\n            # No falling piece in play, so start a new piece at the top\n            fallingPiece = nextPiece\n            nextPiece = getNewPiece()\n            lastFallTime = time.time() # reset lastFallTime\n\n            if not isValidPosition(board, fallingPiece):\n                return # can't fit a new piece on the board, so game over\n\n        checkForQuit()\n        for event in pygame.event.get(): # event handling loop\n            if event.type == KEYUP:\n                if (event.key == K_p):\n                    # Pausing the game\n                    DISPLAYSURF.fill(BGCOLOR)\n                    pygame.mixer.music.stop()\n                    showTextScreen('Paused') # pause until a key press\n                    pygame.mixer.music.play(-1, 0.0)\n                    lastFallTime = time.time()\n                    lastMoveDownTime = time.time()\n                    lastMoveSidewaysTime = time.time()\n                elif (event.key == K_LEFT or event.key == K_a):\n                    movingLeft = False\n                elif (event.key == K_RIGHT or event.key == K_d):\n                    movingRight = False\n                elif (event.key == K_DOWN or event.key == K_s):\n                    movingDown = False\n\n            elif event.type == KEYDOWN:\n                # moving the piece sideways\n                if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):\n                    fallingPiece['x'] -= 1\n                    movingLeft = True\n                    movingRight = False\n                    lastMoveSidewaysTime = time.time()\n\n                elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):\n                    fallingPiece['x'] += 1\n                    movingRight = True\n                    movingLeft = False\n                    lastMoveSidewaysTime = time.time()\n\n                # rotating the piece (if there is room to rotate)\n                elif (event.key == K_UP or event.key == K_w):\n                    fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])\n                    if not isValidPosition(board, fallingPiece):\n                        fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])\n                elif (event.key == K_q): # rotate the other direction\n                    fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])\n                    if not isValidPosition(board, fallingPiece):\n                        fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])\n\n                # making the piece fall faster with the down key\n                elif (event.key == K_DOWN or event.key == K_s):\n                    movingDown = True\n                    if isValidPosition(board, fallingPiece, adjY=1):\n                        fallingPiece['y'] += 1\n                    lastMoveDownTime = time.time()\n\n                # move the current piece all the way down\n                elif event.key == K_SPACE:\n                    movingDown = False\n                    movingLeft = False\n                    movingRight = False\n                    for i in range(1, BOARDHEIGHT):\n                        if not isValidPosition(board, fallingPiece, adjY=i):\n                            break\n                    fallingPiece['y'] += i - 1\n\n        # handle moving the piece because of user input\n        if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:\n            if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):\n                fallingPiece['x'] -= 1\n            elif movingRight and isValidPosition(board, fallingPiece, adjX=1):\n                fallingPiece['x'] += 1\n            lastMoveSidewaysTime = time.time()\n\n        if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):\n            fallingPiece['y'] += 1\n            lastMoveDownTime = time.time()\n\n        # let the piece fall if it is time to fall\n        if time.time() - lastFallTime > fallFreq:\n            # see if the piece has landed\n            if not isValidPosition(board, fallingPiece, adjY=1):\n                # falling piece has landed, set it on the board\n                addToBoard(board, fallingPiece)\n                score += removeCompleteLines(board)\n                level, fallFreq = calculateLevelAndFallFreq(score)\n                fallingPiece = None\n            else:\n                # piece did not land, just move the piece down\n                fallingPiece['y'] += 1\n                lastFallTime = time.time()\n\n        # drawing everything on the screen\n        DISPLAYSURF.fill(BGCOLOR)\n        drawBoard(board)\n        drawStatus(score, level)\n        drawNextPiece(nextPiece)#Here\n        if fallingPiece != None:\n            drawPiece(fallingPiece)\n\n        pygame.display.update()\n        FPSCLOCK.tick(FPS)\n\n\ndef makeTextObjs(text, font, color):\n    surf = font.render(text, True, color)\n    return surf, surf.get_rect()\n\n\ndef terminate():\n    pygame.quit()\n    sys.exit()\n\n\ndef checkForKeyPress():\n    # Go through event queue looking for a KEYUP event.\n    # Grab KEYDOWN events to remove them from the event queue.\n    checkForQuit()\n\n    for event in pygame.event.get([KEYDOWN, KEYUP]):\n        if event.type == KEYDOWN:\n            continue\n        return event.key\n    return None\n\n\ndef showTextScreen(text):\n    # This function displays large text in the\n    # center of the screen until a key is pressed.\n    # Draw the text drop shadow\n    titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)\n    titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))\n    DISPLAYSURF.blit(titleSurf, titleRect)\n\n    # Draw the text\n    titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)\n    titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)\n    DISPLAYSURF.blit(titleSurf, titleRect)\n\n    # Draw the additional \"Press a key to play.\" text.\n    pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)\n    pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)\n    DISPLAYSURF.blit(pressKeySurf, pressKeyRect)\n\n    while checkForKeyPress() == None:\n        pygame.display.update()\n        FPSCLOCK.tick()\n\n\ndef checkForQuit():\n    for event in pygame.event.get(QUIT): # get all the QUIT events\n        terminate() # terminate if any QUIT events are present\n    for event in pygame.event.get(KEYUP): # get all the KEYUP events\n        if event.key == K_ESCAPE:\n            terminate() # terminate if the KEYUP event was for the Esc key\n        pygame.event.post(event) # put the other KEYUP event objects back\n\n\ndef calculateLevelAndFallFreq(score):\n    # Based on the score, return the level the player is on and\n    # how many seconds pass until a falling piece falls one space.\n    level = int(score / 10) + 1\n    fallFreq = 0.27 - (level * 0.02)\n    return level, fallFreq\n\ndef getNewPiece():\n    # return a random new piece in a random rotation and color\n    shape = random.choice(list(PIECES.keys()))\n    newPiece = {'shape': shape,\n                'rotation': random.randint(0, len(PIECES[shape]) - 1),\n                'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),\n                'y': -2, # start it above the board (i.e. less than 0)\n                'color': random.randint(0, len(COLORS)-1)}\n    return newPiece\n\n\ndef addToBoard(board, piece):\n    # fill in the board based on piece's location, shape, and rotation\n    for x in range(TEMPLATEWIDTH):\n        for y in range(TEMPLATEHEIGHT):\n            if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:\n                board[x + piece['x']][y + piece['y']] = piece['color']\n\n\ndef getBlankBoard():\n    # create and return a new blank board data structure\n    board = []\n    for i in range(BOARDWIDTH):\n        board.append([BLANK] * BOARDHEIGHT)\n    return board\n\n\ndef isOnBoard(x, y):\n    return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT\n\n\ndef isValidPosition(board, piece, adjX=0, adjY=0):\n    # Return True if the piece is within the board and not colliding\n    for x in range(TEMPLATEWIDTH):\n        for y in range(TEMPLATEHEIGHT):\n            isAboveBoard = y + piece['y'] + adjY < 0\n            if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:\n                continue\n            if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):\n                return False\n            if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:\n                return False\n    return True\n\ndef isCompleteLine(board, y):\n    # Return True if the line filled with boxes with no gaps.\n    for x in range(BOARDWIDTH):\n        if board[x][y] == BLANK:\n            return False\n    return True\n\n\ndef removeCompleteLines(board):\n    # Remove any completed lines on the board, move everything above them down, and return the number of complete lines.\n    numLinesRemoved = 0\n    y = BOARDHEIGHT - 1 # start y at the bottom of the board\n    while y >= 0:\n        if isCompleteLine(board, y):\n            # Remove the line and pull boxes down by one line.\n            for pullDownY in range(y, 0, -1):\n                for x in range(BOARDWIDTH):\n                    board[x][pullDownY] = board[x][pullDownY-1]\n            # Set very top line to blank.\n            for x in range(BOARDWIDTH):\n                board[x][0] = BLANK\n            numLinesRemoved += 1\n            # Note on the next iteration of the loop, y is the same.\n            # This is so that if the line that was pulled down is also\n            # complete, it will be removed.\n        else:\n            y -= 1 # move on to check next row up\n    return numLinesRemoved\n\n\ndef convertToPixelCoords(boxx, boxy):\n    # Convert the given xy coordinates of the board to xy\n    # coordinates of the location on the screen.\n    return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))\n\n\ndef drawBox(boxx, boxy, color, pixelx=None, pixely=None):\n    # draw a single box (each tetromino piece has four boxes)\n    # at xy coordinates on the board. Or, if pixelx & pixely\n    # are specified, draw to the pixel coordinates stored in\n    # pixelx & pixely (this is used for the \"Next\" piece).\n    if color == BLANK:\n        return\n    if pixelx == None and pixely == None:\n        pixelx, pixely = convertToPixelCoords(boxx, boxy)\n    pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))\n    pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))\n\n\ndef drawBoard(board):\n    # draw the border around the board\n    pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)\n\n    # fill the background of the board\n    pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))\n    # draw the individual boxes on the board\n    for x in range(BOARDWIDTH):\n        for y in range(BOARDHEIGHT):\n            drawBox(x, y, board[x][y])\n\n\ndef drawStatus(score, level):\n    # draw the score text\n    scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)\n    scoreRect = scoreSurf.get_rect()\n    scoreRect.topleft = (WINDOWWIDTH - 150, 20)\n    DISPLAYSURF.blit(scoreSurf, scoreRect)\n\n    # draw the level text\n    levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)\n    levelRect = levelSurf.get_rect()\n    levelRect.topleft = (WINDOWWIDTH - 150, 50)\n    DISPLAYSURF.blit(levelSurf, levelRect)\n\n\ndef drawPiece(piece, pixelx=None, pixely=None):\n    shapeToDraw = PIECES[piece['shape']][piece['rotation']]\n    if pixelx == None and pixely == None:\n        # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure\n        pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])\n\n    # draw each of the boxes that make up the piece\n    for x in range(TEMPLATEWIDTH):\n        for y in range(TEMPLATEHEIGHT):\n            if shapeToDraw[y][x] != BLANK:\n                drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))\n\n\ndef drawNextPiece(piece):\n    # draw the \"next\" text\n    nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)\n    nextRect = nextSurf.get_rect()\n    nextRect.topleft = (WINDOWWIDTH - 120, 80)\n    DISPLAYSURF.blit(nextSurf, nextRect)\n    # draw the \"next\" piece\n    drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "pygame_player.py",
    "content": "import pygame\nimport numpy  # import is unused but required or we fail later\nfrom pygame.constants import K_DOWN, K_UP, KEYDOWN, KEYUP, QUIT\nimport pygame.surfarray\nimport pygame.key\n\n\ndef function_intercept(intercepted_func, intercepting_func):\n    \"\"\"\n    Intercepts a method call and calls the supplied intercepting_func with the result of it's call and it's arguments\n\n    Example:\n        def get_event(result_of_real_event_get, *args, **kwargs):\n            # do work\n            return result_of_real_event_get\n\n        pygame.event.get = function_intercept(pygame.event.get, get_event)\n\n    :param intercepted_func: The function we are going to intercept\n    :param intercepting_func:   The function that will get called after the intercepted func. It is supplied the return\n    value of the intercepted_func as the first argument and it's args and kwargs.\n    :return: a function that combines the intercepting and intercepted function, should normally be set to the\n             intercepted_functions location\n    \"\"\"\n\n    def wrap(*args, **kwargs):\n        real_results = intercepted_func(*args, **kwargs)  # call the function we are intercepting and get it's result\n        intercepted_results = intercepting_func(real_results, *args, **kwargs)  # call our own function a\n        return intercepted_results\n\n    return wrap\n\n\nclass PyGamePlayer(object):\n    def __init__(self, force_game_fps=10, run_real_time=False, pass_quit_event=True):\n        \"\"\"\n        Abstract class for learning agents, such as running reinforcement learning neural nets against PyGame games.\n\n        The get_keys_pressed and get_feedback methods must be overriden by a subclass to use\n\n        Call start method to start playing intercepting PyGame and training our machine\n        :param force_game_fps: Fixes the pygame timer functions so the ai will get input as if it were running at this\n                               fps\n        :type force_game_fps: int\n        :param run_real_time: If True the game will actually run at the force_game_fps speed\n        :type run_real_time: bool\n        :param pass_quit_event: If True the ai will be asked for the quit event\n        :type pass_quit_event: bool\n        \"\"\"\n        self.force_game_fps = force_game_fps\n        \"\"\"Fixes the pygame timer functions so the ai will get input as if it were running at this fps\"\"\"\n        self.run_real_time = run_real_time\n        \"\"\"If True the game will actually run at the force_game_fps speed\"\"\"\n        self.pass_quit_event = pass_quit_event\n        \"\"\"Decides whether the quit event should be passed on to the game\"\"\"\n        self._keys_pressed = []\n        self._last_keys_pressed = []\n        self._playing = False\n        self._default_flip = pygame.display.flip\n        self._default_update = pygame.display.update\n        self._default_event_get = pygame.event.get\n        self._default_time_clock = pygame.time.Clock\n        self._default_get_ticks = pygame.time.get_ticks\n        self._game_time = 0.0\n\n    def get_keys_pressed(self, screen_array, feedback, terminal):\n        \"\"\"\n        Called whenever the screen buffer is refreshed. returns the keys we want pressed in the next until the next\n        screen refresh\n\n        :param screen_array: 3d numpy.array of float. screen_width * screen_height * rgb\n        :param feedback: result of call to get_feedback\n        :param terminal: boolean, True if we have reached a terminal state, meaning the next frame will be a restart\n        :return: a list of the integer values of the keys we want pressed. See pygame.constants for values\n        \"\"\"\n        raise NotImplementedError(\"Please override this method\")\n\n    def get_feedback(self):\n        \"\"\"\n        Overriden method should hook into game events to give feeback to the learning agent\n\n        :return: First = value we want to give as reward/punishment to our learning agent\n                 Second = Boolean true if we have reached a terminal state\n        :rtype: tuple (float, boolean)\n        \"\"\"\n        raise NotImplementedError(\"Please override this method\")\n\n    def start(self):\n        \"\"\"\n        Start playing the game. We will now start listening for screen updates calling our play and reward functions\n        and returning our intercepted key presses\n        \"\"\"\n        if self._playing:\n            raise Exception(\"Already playing\")\n\n        pygame.display.flip = function_intercept(pygame.display.flip, self._on_screen_update)\n        pygame.display.update = function_intercept(pygame.display.update, self._on_screen_update)\n        pygame.event.get = function_intercept(pygame.event.get, self._on_event_get)\n        pygame.time.Clock = function_intercept(pygame.time.Clock, self._on_time_clock)\n        pygame.time.get_ticks = function_intercept(pygame.time.get_ticks, self.get_game_time_ms)\n        # TODO: handle pygame.time.set_timer...\n\n        self._playing = True\n\n    def stop(self):\n        \"\"\"\n        Stop playing the game. Will try and return PyGame to the state it was in before we started\n        \"\"\"\n        if not self._playing:\n            raise Exception(\"Already stopped\")\n\n        pygame.display.flip = self._default_flip\n        pygame.display.update = self._default_update\n        pygame.event.get = self._default_event_get\n        pygame.time.Clock = self._default_time_clock\n        pygame.time.get_ticks = self._default_get_ticks\n\n        self._playing = False\n\n    @property\n    def playing(self):\n        \"\"\"\n        Returns if we are in a state where we are playing/intercepting PyGame calls\n        :return: boolean\n        \"\"\"\n        return self._playing\n\n    @playing.setter\n    def playing(self, value):\n        if self._playing == value:\n            return\n        if self._playing:\n            self.stop()\n        else:\n            self.start()\n\n    def get_ms_per_frame(self):\n        return 1000.0 / self.force_game_fps\n\n    def get_game_time_ms(self):\n        return self._game_time\n\n    def _on_time_clock(self, real_clock, *args, **kwargs):\n        return self._FixedFPSClock(self, real_clock)\n\n    def _on_screen_update(self, _, *args, **kwargs):\n        surface_array = pygame.surfarray.array3d(pygame.display.get_surface())\n        reward, terminal = self.get_feedback()\n        keys = self.get_keys_pressed(surface_array, reward, terminal)\n        self._last_keys_pressed = self._keys_pressed\n        self._keys_pressed = keys\n\n        # now we have processed a frame increment the game timer\n        self._game_time += self.get_ms_per_frame()\n\n    def _on_event_get(self, _, *args, **kwargs):\n        key_up_events = []\n        if len(self._last_keys_pressed) > 0:\n            diff_list = list(set( self._last_keys_pressed) - set(self._keys_pressed))\n            key_up_events = [pygame.event.Event(KEYUP, {\"key\": x}) for x in diff_list] \n\n        key_down_events = [pygame.event.Event(KEYDOWN, {\"key\": x}) for x in self._keys_pressed]\n\n        result = []\n\n        # have to deal with arg type filters\n        if args:\n            if hasattr(args[0], \"__iter__\"):\n                args = args[0]\n\n            for type_filter in args:\n                if type_filter == QUIT:\n                    if type_filter == QUIT:\n                        if self.pass_quit_event:\n                            for e in _:\n                                if e.type == QUIT:\n                                    result.append(e)\n                    else:\n                        pass  # never quit\n                elif type_filter == KEYUP:\n                    result = result + key_up_events\n                elif type_filter == KEYDOWN:\n                    result = result + key_down_events\n        else:\n            result = key_down_events + key_up_events\n            if self.pass_quit_event:\n                for e in _:\n                    if e.type == QUIT:\n                        result.append(e)\n\n        return result\n\n    def __enter__(self):\n        self.start()\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        self.stop()\n\n    class _FixedFPSClock(object):\n        def __init__(self, pygame_player, real_clock):\n            self._pygame_player = pygame_player\n            self._real_clock = real_clock\n\n        def tick(self, _=None):\n            if self._pygame_player.run_real_time:\n                return self._real_clock.tick(self._pygame_player.force_game_fps)\n            else:\n                return self._pygame_player.get_ms_per_frame()\n\n        def tick_busy_loop(self, _=None):\n            if self._pygame_player.run_real_time:\n                return self._real_clock.tick_busy_loop(self._pygame_player.force_game_fps)\n            else:\n                return self._pygame_player.get_ms_per_frame()\n\n        def get_time(self):\n            return self._pygame_player.get_game_time_ms()\n\n        def get_raw_time(self):\n            return self._pygame_player.get_game_time_ms()\n\n        def get_fps(self):\n            return int(1.0 / self._pygame_player.get_ms_per_frame())\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_pygame_player.py",
    "content": "import time\nimport pygame\nfrom unittest import TestCase\nfrom pygame_player import PyGamePlayer\n\n\nclass DummyPyGamePlayer(PyGamePlayer):\n    def __init__(self, force_game_fps=10, run_real_time=False):\n        super(DummyPyGamePlayer, self).__init__(force_game_fps=force_game_fps, run_real_time=run_real_time)\n\n    def get_keys_pressed(self, screen_array, feedback, terminal):\n        pass\n\n    def get_feedback(self):\n        return 0.0, False\n\n\nclass TestPyGamePlayer(TestCase):\n    DISPLAY_X = 1\n    DISPLAY_Y = 1\n\n    def setUp(self):\n        pygame.init()\n        pygame.display.set_mode((self.DISPLAY_X, self.DISPLAY_Y), 0, 32)\n\n    def tearDown(self):\n        pygame.quit()\n\n    def test_restores_pygame_methods_after_exit(self):\n        pygame_flip, pygame_update, pygame_event = pygame.display.flip, pygame.display.update, pygame.event.get\n\n        with PyGamePlayer():\n            # methods should be replaced\n            self.assertNotEqual(pygame_flip, pygame.display.flip)\n            self.assertNotEqual(pygame_update, pygame.display.update)\n            self.assertNotEqual(pygame_event, pygame.event.get)\n\n        # original methods should be restored\n        self.assertEqual(pygame_flip, pygame.display.flip)\n        self.assertEqual(pygame_update, pygame.display.update)\n        self.assertEqual(pygame_event, pygame.event.get)\n\n    def test_fixing_frames_per_second(self):\n        fix_fps_to = 3\n        with DummyPyGamePlayer(force_game_fps=fix_fps_to):\n            clock = pygame.time.Clock()\n            start_time_ms = clock.get_time()\n\n            for _ in range(fix_fps_to):\n                pygame.display.update()\n\n            end_time_ms = clock.get_time()\n\n        self.assertAlmostEqual(end_time_ms - start_time_ms, 1000.0,\n                               msg='Expected only 1000 milliseconds to have passed on the clock after screen updates')\n\n    def test_get_keys_pressed_method_sets_event_get(self):\n        fixed_key_pressed = 24\n\n        class FixedKeysReturned(DummyPyGamePlayer):\n            def get_keys_pressed(self, screen_array, feedback, terminal):\n                return [fixed_key_pressed]\n\n        with FixedKeysReturned():\n            pygame.display.update()\n            key_pressed = pygame.event.get()\n\n        self.assertEqual(key_pressed[0].key, fixed_key_pressed)\n\n    def test_get_screen_buffer(self):\n        class TestScreenArray(DummyPyGamePlayer):\n            def get_keys_pressed(inner_self, screen_array, feedback, terminal):\n                self.assertEqual(screen_array.shape[0], self.DISPLAY_X)\n                self.assertEqual(screen_array.shape[1], self.DISPLAY_Y)\n\n        with TestScreenArray():\n            pygame.display.update()\n\n    def test_run_real_time(self):\n        fix_fps_to = 3\n\n        with PyGamePlayer(force_game_fps=fix_fps_to, run_real_time=True):\n            start = time.time()\n\n            clock = pygame.time.Clock()\n            for _ in range(fix_fps_to):\n                clock.tick(42343)\n\n            end = time.time()\n\n        self.assertAlmostEqual(end-start, 1.0, delta=0.1)\n"
  }
]