'Return the best response action(s) to `opponents_actions`.
Parameters
opponents_actions : scalar(int) or array_like
A profile of N-1 opponents\' actions, represented by either
scalar(int), array_like(float), array_like(int), or
array_like(array_like(float)). If N=2, then it must be a
scalar of integer (in which case it is treated as the
opponent\'s pure action) or a 1-dimensional array of floats
(in which case it is treated as the opponent\'s mixed
action). If N>2, then it must be an array of N-1 objects,
where each object must be an integer (pure action) or an
array of floats (mixed action).
tie_breaking : str, optional(default=\'smallest\')
str in {\'smallest\', \'random\', False}. Control how, or
whether, to break a tie (see Returns for details).
payoff_perturbation : array_like(float), optional(default=None)
Array of length equal to the number of actions of the player
containing the values ("noises") to be added to the payoffs
in determining the best response.
tol : scalar(float), optional(default=None)
Tolerance level used in determining best responses. If None,
default to the value of the `tol` attribute.
random_state : int or np.random.RandomState, optional
Random seed (integer) or np.random.RandomState instance to
set the initial state of the random number generator for
reproducibility. If None, a randomly initialized RandomState
is used. Relevant only when tie_breaking=\'random\'.
Returns
scalar(int) or ndarray(int, ndim=1)
If tie_breaking=False, returns an array containing all the
best response pure actions. If tie_breaking=\'smallest\',
returns the best response action with the smallest index; if
tie_breaking=\'random\', returns an action randomly chosen
from the best response actions.'

def best_response(self, opponents_actions, tie_breaking='smallest', payoff_perturbation=None, tol=None, random_state=None):

    if (tol is None):
        tol = self.tol
    payoff_vector = self.payoff_vector(opponents_actions)
    if (payoff_perturbation is not None):
        try:
            payoff_vector += payoff_perturbation
        except TypeError:
            payoff_vector = (payoff_vector + payoff_perturbation)
    best_responses = np.where((payoff_vector >= (payoff_vector.max() - tol)))[0]
    if (tie_breaking == 'smallest'):
        return best_responses[0]
    elif (tie_breaking == 'random'):
        return self.random_choice(best_responses, random_state=random_state)
    elif (tie_breaking is False):
        return best_responses
    else:
        msg = "tie_breaking    must    be    one    of    'smallest',    'random',    or    False"
        raise ValueError(msg)
