code: def step(self, action):
      # Before applying action(s), there could be chance nodes.
      # E.g. if env has to figure out, which agent's action should get
      # resolved first in a simultaneous node.
      self._solve_chance_nodes()
      penalties = {}
  
      # Sequential game:
      if str(self.type.dynamics) == "Dynamics.SEQUENTIAL":
          curr_player = self.state.current_player()
          assert curr_player in action
          try:
              self.state.apply_action(action[curr_player])
          # TODO: (sven) resolve this hack by publishing legal actions
          #  with each step.
          except pyspiel.SpielError:
              self.state.apply_action(
                  np.random.choice(self.state.legal_actions())
              )
              penalties[curr_player] = -0.1
  
          # Compile rewards dict.
          rewards = {ag: r for ag, r in enumerate(self.state.returns())}
      # Simultaneous game.
      else:
          assert self.state.current_player() == -2
          # Apparently, this works, even if one or more actions are invalid.
          self.state.apply_actions(
              [action[ag] for ag in range(self.num_agents)]
          )
  
      # Now that we have applied all actions, get the next obs.
      obs = self._get_obs()
  
      # Compile rewards dict and add the accumulated penalties
      # (for taking invalid actions).
      rewards = {ag: r for ag, r in enumerate(self.state.returns())}
      for ag, penalty in penalties.items():
          rewards[ag] += penalty
  
      # Are we done?
      is_terminated = self.state.is_terminal()
      terminateds = dict(
          {ag: is_terminated for ag in range(self.num_agents)},
          **{"__all__": is_terminated},
      )
      truncateds = dict(
          {ag: False for ag in range(self.num_agents)},
          **{"__all__": False},
      )
  
      return obs, rewards, terminateds, truncateds, {}
  
file_path: ray/python/ray/rllib/env/wrappers/open_spiel.py
imports: from typing import Optional
  import numpy
  from gymnasium.spaces import Box, Discrete
  from ray.rllib.env.multi_agent_env import MultiAgentEnv
  from ray.rllib.env.utils import try_import_pyspiel
label_desc: Use image node_id 3 for calling the OpenSpielEnv obj's underlying member method code with example usage: obj.step(action) and returns: obs,  rewards,  terminateds,  truncateds,  dict