|
| 1 | +.. _heterogeneous-matches: |
| 2 | + |
| 3 | +Heterogeneous Matches |
| 4 | +===================== |
| 5 | + |
| 6 | +Axelrod Matches are homogeneous by nature but can be extended to utilize additional attributes of heterogeneous players. |
| 7 | +This tutorial indicates how the Axelrod :code:`Match` class can be manipulated in order to play heterogeneous tournaments and Moran processes using country mass as a score modifier. |
| 8 | + |
| 9 | +The following lines of code creates a list of players from the available demo strategies along with an ascending list of values we will use for the players:: |
| 10 | + |
| 11 | + >>> import axelrod as axl |
| 12 | + >>> players = [player() for player in axl.demo_strategies] |
| 13 | + >>> masses = [1 * i for i in range(len(players))] |
| 14 | + >>> players |
| 15 | + [Cooperator, Defector, Tit For Tat, Grudger, Random: 0.5] |
| 16 | + |
| 17 | +Using the :code:`setattr()` method, additional attributes can be passed to players to enable access during matches and tournaments without manual modification of individual strategies:: |
| 18 | + |
| 19 | + >>> def set_player_mass(players, masses): |
| 20 | + >>> """Add mass attribute to player strategy classes to be accessable via self.mass""" |
| 21 | + >>> for player, mass in zip(players, masses): |
| 22 | + >>> setattr(player, "mass", mass) |
| 23 | + >>> |
| 24 | + >>> set_player_mass(players, masses) |
| 25 | + |
| 26 | +The :code:`Match` class can be partially altered to enable different behaviour. Here we extend :code:`axl.Match` and overwrite its :code:`final_score_per_turn()` |
| 27 | +function to utilize the player mass attribute als a multiplier for the final score:: |
| 28 | + |
| 29 | + >>> class MassBaseMatch(axl.Match): |
| 30 | + >>> """Axelrod Match object with a modified final score function to enable mass to influence the final score as a multiplier""" |
| 31 | + >>> def final_score_per_turn(self): |
| 32 | + >>> base_scores = axl.Match.final_score_per_turn(self) |
| 33 | + >>> return [player.mass * score for player, score in zip(self.players, base_scores)] |
| 34 | + |
| 35 | +We can now create a tournament like we normally would and pass our custom :code:`MassBaseMatch` to the tournament with the :code:`match_class` keyword argument:: |
| 36 | + |
| 37 | + >>> tournament = axl.Tournament(players=players, match_class=MassBaseMatch) |
| 38 | + >>> results = tournament.play() |
| 39 | + >>> print(results.ranked_names) |
| 40 | + ['Defector', 'Grudger', 'Tit For Tat', 'Cooperator', 'Random: 0.5'] |
| 41 | + |
| 42 | +Additionally, Moran Processes can also be altered to incorporate heterogeneous matches. In order to |
| 43 | +use our previously defined :code:`MassBaseMatch`, we require one additional change to the :code:`MoranProcess` class:: |
| 44 | + |
| 45 | + >>> class MassBasedMoranProcess(axl.MoranProcess): |
| 46 | + >>> """Axelrod MoranProcess class """ |
| 47 | + >>> def __next__(self): |
| 48 | + >>> set_player_mass(self.players, masses) |
| 49 | + >>> super().__next__() |
| 50 | + >>> return self |
| 51 | + |
| 52 | +With this code snippet we can override the :code:`__next__()` call within the MoranProcess to include :code:`set_player_mass()` |
| 53 | +every round. This ensures that every player has mass attributes after the Moran process is triggered. |
| 54 | +Subsequently, with :code:`super().__next__()` the base MoranProcess :code:`__next__()` call is triggered. This method enables quick |
| 55 | +modifications to tournaments and moran processes with minimal repetitive code. |
| 56 | + |
| 57 | +We can now create a Moran process as we normally would, with the inclusion of the match class as a keyword argument:: |
| 58 | + |
| 59 | + >>> mp = MassBasedMoranProcess(players, match_class=MassBaseMatch) |
| 60 | + >>> mp.play() |
| 61 | + >>> print(mp.winning_strategy_name) |
| 62 | + Grudger |
| 63 | + |
| 64 | +Note that the snippets here only influence the final score of matches. The behavior of matches, tournaments and moran |
| 65 | +processes can be more heavily influenced by partially overwriting other :code:`match` functions or :code:`birth` and :code:`death` functions within :code:`MoranProcess`. |
0 commit comments