diff --git a/axelrod/strategies/_strategies.py b/axelrod/strategies/_strategies.py index b32399caf..3c121fbb3 100644 --- a/axelrod/strategies/_strategies.py +++ b/axelrod/strategies/_strategies.py @@ -7,7 +7,7 @@ from .axelrod_first import ( Davis, RevisedDowning, Feld, Grofman, Nydegger, Joss, Shubik, Tullock, UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi) -from .axelrod_second import Champion, Eatherley, Tester, Gladstein, Tranquilizer +from .axelrod_second import Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman from .backstabber import BackStabber, DoubleCrosser from .better_and_better import BetterAndBetter from .calculator import Calculator @@ -197,6 +197,7 @@ MindReader, MindWarper, MirrorMindReader, + MoreGrofman, Negation, NiceAverageCopier, NTitsForMTats, diff --git a/axelrod/strategies/axelrod_second.py b/axelrod/strategies/axelrod_second.py index 37dd94a6f..e32e8063c 100644 --- a/axelrod/strategies/axelrod_second.py +++ b/axelrod/strategies/axelrod_second.py @@ -410,3 +410,60 @@ def strategy(self, opponent: Player) -> Action: return C return D return opponent.history[-1] + + +class MoreGrofman(Player): + """ + Submitted to Axelrod's second tournament by Bernard Grofman. + + This strategy has 3 phases: + + 1. First it cooperates on the first two rounds + 2. For rounds 3-7 inclusive, it plays the same as the opponent's last move + 3. Thereafter, it applies the following logic, looking at its memory of the + last 8\* rounds (ignoring the most recent round). + + - If its own previous move was C and the opponent has defected less than + 3 times in the last 8\* rounds, cooperate + - If its own previous move was C and the opponent has defected 3 or + more times in the last 8\* rounds, defect + - If its own previous move was D and the opponent has defected only once + or not at all in the last 8\* rounds, cooperate + - If its own previous move was D and the opponent has defected more than + once in the last 8\* rounds, defect + + \* The code looks at the first 7 of the last 8 rounds, ignoring the most + recent round. + + Names: + - Grofman's strategy: [Axelrod1980b]_ + - K86R: [Axelrod1980b]_ + """ + name = "MoreGrofman" + classifier = { + 'memory_depth': 8, + 'stochastic': False, + 'makes_use_of': set(), + 'long_run_time': False, + 'inspects_source': False, + 'manipulates_source': False, + 'manipulates_state': False + } + + def strategy(self, opponent: Player) -> Action: + # Cooperate on the first two moves + if len(self.history) < 2: + return C + # For rounds 3-7, play the opponent's last move + elif 2 <= len(self.history) <= 6: + return opponent.history[-1] + else: + # Note: the Fortran code behavior ignores the opponent behavior + # in the last round and instead looks at the first 7 of the last + # 8 rounds. + opponent_defections_last_8_rounds = opponent.history[-8:-1].count(D) + if self.history[-1] == C and opponent_defections_last_8_rounds <= 2: + return C + if self.history[-1] == D and opponent_defections_last_8_rounds <= 1: + return C + return D diff --git a/axelrod/tests/strategies/test_axelrod_second.py b/axelrod/tests/strategies/test_axelrod_second.py index 302c2678e..fdefb7073 100644 --- a/axelrod/tests/strategies/test_axelrod_second.py +++ b/axelrod/tests/strategies/test_axelrod_second.py @@ -160,7 +160,6 @@ def test_strategy(self): self.versus_test(opponent, expected_actions=actions, attrs={'patsy': False}) - class TestTranquilizer(TestPlayer): name = "Tranquilizer" @@ -175,7 +174,6 @@ class TestTranquilizer(TestPlayer): 'manipulates_state': False } - # test for initalised variables def test_init(self): @@ -330,3 +328,83 @@ def test_strategy(self): "two_turns_after_good_defection_ratio_count": 1} self.versus_test(opponent, expected_actions=actions, attrs=expected_attrs) + + +class TestMoreGrofman(TestPlayer): + + name = "MoreGrofman" + player = axelrod.MoreGrofman + expected_classifier = { + 'memory_depth': 8, + 'stochastic': False, + 'makes_use_of': set(), + 'long_run_time': False, + 'inspects_source': False, + 'manipulates_source': False, + 'manipulates_state': False + } + + def test_strategy(self): + # Cooperate for the first two rounds + actions = [(C, C), (C, C)] + self.versus_test(axelrod.Cooperator(), expected_actions=actions) + + # Cooperate for the first two rounds, then play tit for tat for 3-7 + actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D), (D, C)] + self.versus_test(axelrod.Alternator(), expected_actions=actions) + + # Demonstrate MoreGrofman Logic + # Own previous move was C, opponent defected less than 3 times in last 8 + moregrofman_actions = [C] * 7 + [C] + opponent_actions = [C] * 6 + [D] * 2 + opponent = axelrod.MockPlayer(actions=opponent_actions) + actions = list(zip(moregrofman_actions, opponent_actions)) + self.versus_test(opponent, expected_actions=actions) + + # Own previous move was C, opponent defected 3 or more times in last 8 + moregrofman_actions = ([C] * 3 + [D] * 3 + [C]) + [D] + opponent_actions = ([C] * 2 + [D] * 3 + [C] * 2) + [D] + opponent = axelrod.MockPlayer(actions=opponent_actions) + actions = list(zip(moregrofman_actions, opponent_actions)) + self.versus_test(opponent, expected_actions=actions) + + # Own previous move was D, opponent defected once or less in last 8 + moregrofman_actions = ([C] * 6 + [D]) + [C] + opponent_actions = ([C] * 5 + [D] * 1 + [C]) + [D] + opponent = axelrod.MockPlayer(actions=opponent_actions) + actions = list(zip(moregrofman_actions, opponent_actions)) + self.versus_test(opponent, expected_actions=actions) + + # Own previous move was D, opponent defected more than once in last 8 + moregrofman_actions = ([C] * 2 + [D] * 5) + [D] + opponent_actions = ([D] * 7) + [D] + opponent = axelrod.MockPlayer(actions=opponent_actions) + actions = list(zip(moregrofman_actions, opponent_actions)) + self.versus_test(opponent, expected_actions=actions) + + # Test to make sure logic matches Fortran (discrepancy found 8/23/2017) + opponent = axelrod.AntiTitForTat() + # Actions come from a match run by Axelrod Fortran using Player('k86r') + actions = [(C, C), (C, D), (D, D), (D, C), (C, C), (C, D), (D, D), + (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (C, C)] + self.versus_test(opponent, expected_actions=actions) + + # Test to match the Fortran implementation for 30 rounds + opponent = axelrod.AntiTitForTat() + actions = [(C, C), (C, D), (D, D), (D, C), (C, C), (C, D), (D, D), + (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (C, C), + (C, D), (C, D), (C, D), (C, D), (D, D), (D, C), (D, C), (D, C), + (D, C), (D, C), (D, C), (D, C), (C, C), (C, D), (C, D)] + self.versus_test(opponent, expected_actions=actions) + + # Test to match the Fortran implementation for 60 rounds + opponent = axelrod.AntiTitForTat() + actions = [(C, C), (C, D), (D, D), (D, C), (C, C), (C, D), (D, D), + (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (C, C), + (C, D), (C, D), (C, D), (C, D), (D, D), (D, C), (D, C), (D, C), + (D, C), (D, C), (D, C), (D, C), (C, C), (C, D), (C, D), (C, D), + (C, D), (D, D), (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), + (D, C), (C, C), (C, D), (C, D), (C, D), (C, D), (D, D), (D, C), + (D, C), (D, C), (D, C), (D, C), (D, C), (D, C), (C, C), (C, D), + (C, D), (C, D), (C, D), (D, D), (D, C)] + self.versus_test(opponent, expected_actions=actions)