diff --git a/axelrod/strategies/_strategies.py b/axelrod/strategies/_strategies.py index 752e56f20..05c0408ed 100644 --- a/axelrod/strategies/_strategies.py +++ b/axelrod/strategies/_strategies.py @@ -142,6 +142,7 @@ GrudgerAlternator, OppositeGrudger, SoftGrudger, + SpitefulCC, ) from .grumpy import Grumpy from .handshake import Handshake @@ -467,6 +468,7 @@ SolutionB1, SolutionB5, SpitefulTitForTat, + SpitefulCC, Stalker, StochasticCooperator, StochasticWSLS, diff --git a/axelrod/strategies/grudger.py b/axelrod/strategies/grudger.py index a646851af..c4e197e1c 100644 --- a/axelrod/strategies/grudger.py +++ b/axelrod/strategies/grudger.py @@ -24,7 +24,7 @@ class Grudger(Player): name = "Grudger" classifier = { - "memory_depth": float('inf'), + "memory_depth": float("inf"), "stochastic": False, "long_run_time": False, "inspects_source": False, @@ -310,3 +310,35 @@ def strategy(self, opponent: Player) -> Action: def __repr__(self) -> str: return "%s: n=%s,d=%s,c=%s" % (self.name, self.n, self.d, self.c) + + +class SpitefulCC(Player): + """ + Behaves like Grudger after cooperating for 2 turns + + Names: + + - spiteful_cc: [Mathieu2015]_ + """ + + name = "SpitefulCC" + classifier = { + "memory_depth": float("inf"), # Long memory + "stochastic": False, + "long_run_time": False, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + @staticmethod + def strategy(opponent: Player) -> Action: + """ + Cooperates until the oponent defects, then defects forever. + Always cooperates twice at the start. + """ + if len(opponent.history) < 2: + return C + elif opponent.defections: + return D + return C diff --git a/axelrod/tests/strategies/test_grudger.py b/axelrod/tests/strategies/test_grudger.py index 79194b5d8..9bd980b89 100644 --- a/axelrod/tests/strategies/test_grudger.py +++ b/axelrod/tests/strategies/test_grudger.py @@ -12,7 +12,7 @@ class TestGrudger(TestPlayer): name = "Grudger" player = axl.Grudger expected_classifier = { - "memory_depth": float('inf'), + "memory_depth": float("inf"), "stochastic": False, "makes_use_of": set(), "long_run_time": False, @@ -276,3 +276,34 @@ def test_strategy(self): expected_actions=actions, init_kwargs={"n": 1, "d": 1, "c": 1}, ) + + +class TestSpitefulCC(TestPlayer): + + name = "SpitefulCC" + player = axl.SpitefulCC + expected_classifier = { + "memory_depth": float("inf"), # Long memory + "stochastic": False, + "makes_use_of": set(), + "long_run_time": False, + "inspects_source": False, + "manipulates_source": False, + "manipulates_state": False, + } + + def test_strategy(self): + # If opponent defects at any point then the player will defect forever. + # Cooperates for the first 2 turns. + opponent = axl.Cooperator() + actions = [(C, C)] * 20 + self.versus_test(opponent, expected_actions=actions) + + opponent = axl.Defector() + actions = [(C, D)] * 2 + [(D, D)] * 20 + self.versus_test(opponent, expected_actions=actions) + + opponent_actions = [D] * 20 + [C] * 20 + opponent = axl.MockPlayer(actions=opponent_actions) + actions = [(C, D)] * 2 + [(D, D)] * 18 + [(D, C)] * 20 + self.versus_test(opponent, expected_actions=actions) diff --git a/axelrod/tests/strategies/test_meta.py b/axelrod/tests/strategies/test_meta.py index 6ec22db6b..971dae521 100644 --- a/axelrod/tests/strategies/test_meta.py +++ b/axelrod/tests/strategies/test_meta.py @@ -638,7 +638,7 @@ def classifier_test(self, expected_class_classifier=None): pass def test_strategy(self): - actions = [(C, C), (C, D), (D, C), (D, D), (D, C)] + actions = [(C, C), (C, D), (C, C), (D, D), (D, C)] self.versus_test(opponent=axl.Alternator(), expected_actions=actions, seed=11) diff --git a/docs/index.rst b/docs/index.rst index a0f933d12..f1f5c73ef 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -53,7 +53,7 @@ Count the number of available players:: >>> import axelrod as axl >>> len(axl.strategies) - 236 + 237 Create matches between two players:: @@ -111,4 +111,3 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` -