class_docstr: <a id="GameEnvironment"></a>
  
  ## Game environment
  
  This is a wrapper for OpenAI gym game environment.
  We do a few things here:
  
  1. Apply the same action on four frames and get the last frame
  2. Convert observation frames to gray and scale it to (84, 84)
  3. Stack four frames of the last four actions
  4. Add episode information (total reward for the entire episode) for monitoring
  5. Restrict an episode to a single life (game has 5 lives, we reset after every single life)
  
  #### Observation format
  Observation is tensor of size (4, 84, 84). It is four frames
  (images of the game screen) stacked on first axis.
  i.e, each channel is a frame.
class_docstr_tok: ["<","a","id=","''","GameEnvironment","''",">","<","\/a",">","#","#","Game","environment","This","is","a","wrapper","for","OpenAI","gym","game","environment",".","We","do","a","few","things","here",":","1",".","Apply","the","same","action","on","four","frames","and","get","the","last","frame","2",".","Convert","observation","frames","to","gray","and","scale","it","to","(","84",",","84",")","3",".","Stack","four","frames","of","the","last","four","actions","4",".","Add","episode","information","(","total","reward","for","the","entire","episode",")","for","monitoring","5",".","Restrict","an","episode","to","a","single","life","(","game","has","5","lives",",","we","reset","after","every","single","life",")","#","#","#","#","Observation","format","Observation","is","tensor","of","size","(","4",",","84",",","84",")",".","It","is","four","frames","(","images","of","the","game","screen",")","stacked","on","first","axis",".","i.e",",","each","channel","is","a","frame","."]
docstr: ### Step
  Executes `action` for 4 time steps and
   returns a tuple of (observation, reward, done, episode_info).
  
  * `observation`: stacked 4 frames (this frame and frames for last 3 actions)
  * `reward`: total reward while the action was executed
  * `done`: whether the episode finished (a life lost)
  * `episode_info`: episode information if completed
docstr_tok: ["#","#","#","Step","Executes","`","action","`","for","4","time","steps","and","returns","a","tuple","of","(","observation",",","reward",",","done",",","episode_info",")",".","*","`","observation","`",":","stacked","4","frames","(","this","frame","and","frames","for","last","3","actions",")","*","`","reward","`",":","total","reward","while","the","action","was","executed","*","`","done","`",":","whether","the","episode","finished","(","a","life","lost",")","*","`","episode_info","`",":","episode","information","if","completed"]
code: def step(self, action):
      """
      ### Step
      Executes `action` for 4 time steps and
       returns a tuple of (observation, reward, done, episode_info).
  
      * `observation`: stacked 4 frames (this frame and frames for last 3 actions)
      * `reward`: total reward while the action was executed
      * `done`: whether the episode finished (a life lost)
      * `episode_info`: episode information if completed
      """
  
      reward = 0.0
      done = None
  
      # run for 4 steps
      for i in range(4):
          # execute the action in the OpenAI Gym environment
          obs, r, done, info = self.env.step(action)
  
          if i >= 2:
              self.obs_2_max[i % 2] = self._process_obs(obs)
  
          reward += r
  
          # get number of lives left
          lives = self.env.unwrapped.ale.lives()
          # reset if a life is lost
          if lives < self.lives:
              done = True
              break
  
      # maintain rewards for each step
      self.rewards.append(reward)
  
      if done:
          # if finished, set episode information if episode is over, and reset
          episode_info = {
              "reward": sum(self.rewards),
              "length": len(self.rewards),
          }
          self.reset()
      else:
          episode_info = None
  
          # get the max of last two frames
          obs = self.obs_2_max.max(axis=0)
  
          # push it to the stack of 4 frames
          self.obs_4 = np.roll(self.obs_4, shift=-1, axis=0)
          self.obs_4[-1] = obs
  
      return self.obs_4, reward, done, episode_info
  
file_path: annotated_deep_learning_paper_implementations/labml_nn/rl/game.py
imports: import multiprocessing
  import multiprocessing.connection
  import cv2
  import gym
  import numpy
label_desc: Use image node_id 2 for calling the Game obj's underlying member method code with example usage: obj.step(action) and returns: self,  reward,  done,  episode_info