text: """Polymorphic strategies are strategies that may change between the
  generational cycles of the population dynamical process.
  
  One type of polymorphic strategies are meta strategies that imitate one of the
  ordinary strategies and that can change the strategy they imitate
  between the generational cycles of the population dynamical simulation.
  
  The most common meta strategy would be 'copy the best', i.e.
  a polymorphic strategy that imitates an arbitrary ordinary strategy
  in the first generation and always imitates the strategy with the greatest
  evolutionary success in following generations.
  
  Another type of polymorphic strategies could be evolutionary strategies that
  are base on genetic algorithms.
  """
  
  
  import random, copy
  from Strategies import *
  
  
  ###############################################################################
  #
  # Base class for polymorphic strategies
  #
  ###############################################################################
  
  class PolymorphicStrategy(Strategy):
      """Abstract base class for all polymorphic strategies.
      """ 
      def evolve(self, deme):
          """Adjusts the polymorphic strategy."""
          raise NotImplementedError
  
  
  
  ###############################################################################
  #
  # Base class for meta strategies
  #
  ###############################################################################
  
  class MetaStrategy(PolymorphicStrategy):
      """Abstract base class for all meta strategies.
  
      Attributes:
          snatched  - the ordinary strategy that is imitated by the
                      polymorphic strategy.
      """
      def __init__(self):
          PolymorphicStrategy.__init__(self)
          self.snatched = None
          self.snatch(TitForTat())
  
          # for debugging only:
          self.generationCounter = 0
  
      def _pick(self, strategies, performances):
          """Snatches the strategy with the best performance.
          If there are several equally good strategies, then if the
          "snatched" strategy is among them it is picked. Otherwise a
          strategy is picked randomly from the best strategies.
          """
          ## debugging:
          self.generationCounter += 1
          
          ranking = [(strategies[i], performances[i]) \
                     for i in xrange(len(strategies)) \
                     if not isinstance(strategies[i], PolymorphicStrategy)]
          ranking.sort(key = lambda x: -x[1])
          bestP = ranking[0][1]
          snatchedName = str(self.snatched)
          i = 0; l = []
          while i < len(ranking) and ranking[i][1] == bestP:
              l.append(str(ranking[i][0]) == snatchedName)
              if str(ranking[i][0]) == snatchedName: return
              i += 1
          selected = random.choice(ranking[:i])[0]
          # print ["%s (%f)"%(str(s),f) for s,f in ranking]
          # print str(self.generationCounter) + ", " + str(self)+": "+str(self.snatched)+" -> "+str(selected)       
          self.snatch(selected)
  
      def register(self, simSetup):
          self.snatched.register(simSetup)
  
      def firstMove(self):
          return self.snatched.firstMove()
  
      def nextMove(self, myMoves, opMoves):
          return self.snatched.nextMove(myMoves, opMoves)
  
      def evolve(self, deme):
          raise NotImplementedError
      
      def snatch(self, stgy):
          """Imitate the strategy 'stgy' in the following generations."""
          assert not isinstance(stgy, PolymorphicStrategy), \
              "Polymorphic strategies cannot be imitated themselves."      
          self.snatched = copy.copy(stgy)
          self.randomizing = stgy.randomizing
  
  
  ################################################################################
  #
  # Copy the Best, Copy the Majority
  #
  ################################################################################
  
  class CopyTheBest(MetaStrategy):
      """A meta strategy that copies the best ordinary strategy, i.e.
      the ordinary strategy which has the highest fitness.
      """
      def evolve(self, deme):
          self._pick(deme.species, deme.fitness())
  
  
  class CopyTheMajority(MetaStrategy):
      """A meta strategy that copies the ordinary strategy with the highest
      population share.
      """
      def evolve(self, deme):
          self._pick(deme.species, deme.distribution)
  
  
  _copythebest = CopyTheBest()
  _copythemajority = CopyTheMajority()
  