'Given a list of states, evaluates them all at once to make best use of GPU
batching capabilities.
Analogous to [eval_state(s) for s in states]
Returns: a parallel list of move distributions as in eval_state'

def batch_eval_state(self, states, moves_lists=None):

    n_states = len(states)
    if (n_states == 0):
        return []
    state_size = states[0].size
    if (not all([(st.size == state_size) for st in states])):
        raise ValueError('all    states    must    have    the    same    size')
    nn_input = np.concatenate([self.preprocessor.state_to_tensor(s) for s in states], axis=0)
    network_output = self.forward(nn_input)
    moves_lists = (moves_lists or [st.get_legal_moves() for st in states])
    results = ([None] * n_states)
    for i in range(n_states):
        results[i] = self._select_moves_and_normalize(network_output[i], moves_lists[i], state_size)
    return results
