88
99import inspect
1010import random
11- from types import FunctionType
11+ import collections
12+ from numpy .random import choice
1213
1314from .actions import Actions , flip_action
1415from .random_ import random_choice
@@ -239,6 +240,46 @@ def apology_wrapper(player, opponent, action, myseq, opseq):
239240ApologyTransformer = StrategyTransformerFactory (apology_wrapper ,
240241 name_prefix = "Apologizing" )
241242
243+
244+ def mixed_wrapper (player , opponent , action , probability , m_player ):
245+ """Randomly picks a strategy to play, either from a distribution on a list
246+ of players or a single player.
247+
248+ In essence creating a mixed strategy.
249+
250+ Parameters
251+ ----------
252+
253+ probability: a float (or integer: 0 or 1) OR an iterable representing a
254+ an incomplete probability distribution (entries to do not have to sum to
255+ 1). Eg: 0, 1, [.5,.5], (.5,.3)
256+ m_players: a single player class or iterable representing set of player
257+ classes to mix from.
258+ Eg: axelrod.TitForTat, [axelod.Cooperator, axelrod.Defector]
259+ """
260+
261+ # If a single probability, player is passed
262+ if isinstance (probability , float ) or isinstance (probability , int ):
263+ m_player = [m_player ]
264+ probability = [probability ]
265+
266+ # If a probability distribution, players is passed
267+ if isinstance (probability , collections .Iterable ) and \
268+ isinstance (m_player , collections .Iterable ):
269+ mutate_prob = sum (probability ) # Prob of mutation
270+ if mutate_prob > 0 :
271+ # Distribution of choice of mutation:
272+ normalised_prob = [prob / float (mutate_prob )
273+ for prob in probability ]
274+ if random .random () < mutate_prob :
275+ p = choice (list (m_player ), p = normalised_prob )()
276+ p .history = player .history
277+ return p .strategy (opponent )
278+
279+ return action
280+
281+ MixedTransformer = StrategyTransformerFactory (mixed_wrapper , name_prefix = "Mutated" )
282+
242283# Strategy wrappers as classes
243284
244285class RetaliationWrapper (object ):
@@ -260,6 +301,7 @@ def __call__(self, player, opponent, action, retaliations):
260301RetaliationTransformer = StrategyTransformerFactory (
261302 RetaliationWrapper (), name_prefix = "Retaliating" )
262303
304+
263305class RetaliationUntilApologyWrapper (object ):
264306 """Enforces the TFT rule that the opponent pay back a defection with a
265307 cooperation for the player to stop defecting."""
0 commit comments