class_docstr: Applies a legal actions mask to a linear chain of modules / callables.
  
  It is assumed the trailing dimension of the final layer (representing
  action values) is the same as the trailing dimension of legal_actions.
code: def __call__(self, inputs: open_spiel_wrapper.OLT) -> tf.Tensor:
      # Extract observation, legal actions, and terminal
      outputs = inputs.observation
      legal_actions = inputs.legal_actions
      terminal = inputs.terminal
  
      for mod in self._layers:
          outputs = mod(outputs)
  
      # Apply legal actions mask
      outputs = tf.where(
          tf.equal(legal_actions, 1),
          outputs,
          tf.fill(tf.shape(outputs), self._illegal_action_penalty),
      )
  
      # When computing the Q-learning target (r_t + d_t * max q_t) we need to
      # ensure max q_t = 0 in terminal states.
      outputs = tf.where(
          tf.equal(terminal, 1), tf.zeros_like(outputs), outputs
      )
  
      return outputs
  
file_path: acme/acme/tf/networks/legal_actions.py
imports: from typing import Any, Callable, Iterable, Optional, Union
  from acme.wrappers import open_spiel_wrapper
  import numpy
  import sonnet
  import tensorflow
  import tensorflow_probability
label_desc: Use image node_id 2 for calling the MaskedSequential obj's underlying member method code with example usage: obj.__call__(inputs) and returns: outputs