diff --git a/axelrod/strategies/_strategies.py b/axelrod/strategies/_strategies.py index c0b0abd46..e4faca977 100644 --- a/axelrod/strategies/_strategies.py +++ b/axelrod/strategies/_strategies.py @@ -9,7 +9,7 @@ UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi) from .axelrod_second import ( Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman, - Kluepfel, Borufsen, Cave) + Kluepfel, Borufsen, Cave, WmAdams) from .backstabber import BackStabber, DoubleCrosser from .better_and_better import BetterAndBetter from .bush_mosteller import BushMosteller @@ -274,6 +274,7 @@ Winner21, WinShiftLoseStay, WinStayLoseShift, + WmAdams, WorseAndWorse, WorseAndWorse2, WorseAndWorse3, diff --git a/axelrod/strategies/axelrod_second.py b/axelrod/strategies/axelrod_second.py index ed06e9348..3ea80b7b9 100644 --- a/axelrod/strategies/axelrod_second.py +++ b/axelrod/strategies/axelrod_second.py @@ -755,9 +755,9 @@ def strategy(self, opponent: Player) -> Action: turn = len(self.history) + 1 if turn == 1: return C - did_d = np.vectorize(lambda action: float(action == D)) - number_defects = np.sum(did_d(opponent.history)) - perc_defects = number_defects / turn # Size of numerator is smaller than denomator -- How it was in the Fortran. + number_defects = opponent.defections + # Size of numerator is smaller than denomator -- How it was in the Fortran. + perc_defects = number_defects / turn # If overly defect or appears random if turn > 39 and perc_defects > 0.39: return D @@ -771,3 +771,41 @@ def strategy(self, opponent: Player) -> Action: return random_choice(0.5) else: return C + +class WmAdams(Player): + """ + Strategy submitted to Axelrod's second tournament by William Adams (K44R), + and came in fifth in that tournament. + + Count the number of opponent defections after their first move, call + `c_defect`. Defect if c_defect equals 4, 7, or 9. If c_defect > 9, + then defect immediately after opponent defects with probability = + (0.5)^(c_defect-1). Otherwise cooperate. + + Names: + + - WmAdams: [Axelrod1980b]_ + """ + + name = "WmAdams" + classifier = { + 'memory_depth': float('inf'), + 'stochastic': True, + 'makes_use_of': set(), + 'long_run_time': False, + 'inspects_source': False, + 'manipulates_source': False, + 'manipulates_state': False + } + + def strategy(self, opponent: Player) -> Action: + if len(self.history) <= 1: + return C + number_defects = opponent.defections + if opponent.history[0] == D: + number_defects -= 1 + + if number_defects in [4, 7, 9]: return D + if number_defects > 9 and opponent.history[-1] == D: + return random_choice((0.5) ** (number_defects - 9)) + return C diff --git a/axelrod/tests/strategies/test_axelrod_second.py b/axelrod/tests/strategies/test_axelrod_second.py index d56cf9e6f..aa73106bc 100644 --- a/axelrod/tests/strategies/test_axelrod_second.py +++ b/axelrod/tests/strategies/test_axelrod_second.py @@ -442,14 +442,15 @@ def test_strategy(self): # Now we have to test the detect-random logic, which doesn't pick up # until after 26 turns. So we need a big sample. - actions = [(C, D), (D, D), (D, D), (D, D), (D, D), (D, C), (C, C), (C, D), - (C, C), (D, D), (D, C), (C, C), (C, D), (D, D), (C, D), (D, D), - (D, C), (C, C), (D, C), (C, C), (C, D), (D, D), (D, C), (C, D), - (D, C), (C, C), (C, D), + actions = [(C, D), (D, D), (D, D), (D, D), (D, D), (D, C), (C, C), + (C, D), (C, C), (D, D), (D, C), (C, C), (C, D), (D, D), + (C, D), (D, D), (D, C), (C, C), (D, C), (C, C), (C, D), + (D, D), (D, C), (C, D), (D, C), (C, C), (C, D), # Success detect random opponent for remaining turns. - (D, D),(D, D),(D, D),(D, C),(D, D),(D, C),(D, D),(D, C),(D, D), - (D, C),(D, C),(D, D),(D, D),(D, C),(D, C),(D, C),(D, C),(D, D), - (D, C),(D, C),(D, C),(D, C),(D, D)] + (D, D), (D, D), (D, D), (D, C), (D, D), (D, C), (D, D), + (D, C), (D, D), (D, C), (D, C), (D, D), (D, D), (D, C), + (D, C), (D, C), (D, C), (D, D), (D, C), (D, C), (D, C), + (D, C), (D, D)] self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=10) class TestBorufsen(TestPlayer): @@ -475,16 +476,21 @@ def test_strategy(self): self.versus_test(axelrod.Defector(), expected_actions=actions) # Alternates with additional coop, every sixth turn - # Won't be labeled as random, since 2/3 of opponent's C follow player's C - # `flip_next_defect` will get set on the sixth turn, which changes the seventh action + # Won't be labeled as random, since 2/3 of opponent's C follow + # player's C + # `flip_next_defect` will get set on the sixth turn, which changes the + # seventh action # Note that the first two turns of each period of six aren't - # marked as echoes, and the third isn't marked that way until the fourth turn. + # marked as echoes, and the third isn't marked that way until the + # fourth turn. actions = [(C, C), (C, D), (D, C), (C, D), (D, C), (C, D)] * 20 self.versus_test(axelrod.Alternator(), expected_actions=actions) # Basically does tit-for-tat against Win-Shift, Lose-Stay D - # After 26 turns, will detect random since half of opponent's C follow Cs - # Coming out of it, there will be new pattern. Then random is detected again. + # After 26 turns, will detect random since half of opponent's C follow + # Cs + # Coming out of it, there will be new pattern. Then random is detected + # again. actions = [(C, D), (D, C), (C, C)] * 8 + \ [(C, D), (D, C)] + [(D, C)] * 25 + \ [(D, C)] + [(C, C), (C, D), (D, C)] * 8 + \ @@ -505,7 +511,7 @@ class TestCave(TestPlayer): } def test_strategy(self): - actions = [(C, C)] * 100 + actions = [(C, C)] * 100 self.versus_test(axelrod.Cooperator(), expected_actions=actions) # It will take until turn 18 to respond decide to repond D->D @@ -531,11 +537,51 @@ def test_strategy(self): #Here it will take until turn 40 to detect random and defect actions = [(C, C)] - actions += [(C, D), (D, C), (C, D), (D, C), (C, D), (C, C), (C, D), - (C, C), (C, D), (D, C), (C, D), (D, C), (C, D), (D, C), - (C, D), (C, C), (C, D), (D, C), (C, D), (D, C), (C, D), - (D, C), (C, D), (C, C), (C, D), (C, C), (C, D), (C, C), - (C, D), (D, C), (C, D), (D, C), (C, D), (D, C), (C, D)] #Randomly choose + actions += [(C, D), (D, C), (C, D), (D, C), (C, D), (C, C), (C, D), + (C, C), (C, D), (D, C), (C, D), (D, C), (C, D), (D, C), + (C, D), (C, C), (C, D), (D, C), (C, D), (D, C), (C, D), + (D, C), (C, D), (C, C), (C, D), (C, C), (C, D), (C, C), + (C, D), (D, C), (C, D), (D, C), (C, D), (D, C), (C, D)] #Randomly choose actions += [(D, C), (C, D), (D, C)] # 17 D have come, so tit for tat for a while actions += [(D, D), (D, C)] * 100 # Random finally detected self.versus_test(axelrod.Alternator(), expected_actions=actions, seed=2) + +class TestWmAdams(TestPlayer): + name = "WmAdams" + player = axelrod.WmAdams + expected_classifier = { + 'memory_depth': float('inf'), + 'stochastic': True, + 'makes_use_of': set(), + 'long_run_time': False, + 'inspects_source': False, + 'manipulates_source': False, + 'manipulates_state': False + } + + def test_strategy(self): + actions = [(C, C)] * 100 # Cooperate forever + self.versus_test(axelrod.Cooperator(), expected_actions=actions) + + # Will ignore the first four defects + opponent_actions = [D] * 4 + [C] * 100 + defect_four = axelrod.MockPlayer(actions=opponent_actions) + actions = [(C, D)] * 4 + [(C, C)] * 100 + self.versus_test(defect_four, expected_actions=actions) + + actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D), + (C, D), (D, D), (C, D), (D, D), (C, D), (D, D), (D, D), + (D, D), (D, D)] + self.versus_test(axelrod.Defector(), expected_actions=actions, seed=1) + actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D), + (C, D), (D, D), (C, D), (D, D), (D, D), (D, D), (C, D), + (D, D), (D, D)] + self.versus_test(axelrod.Defector(), expected_actions=actions, seed=2) + + # After responding to the 11th D (counted as 10 D), just start cooperating + opponent_actions = [D] * 11 + [C] * 100 + changed_man = axelrod.MockPlayer(actions=opponent_actions) + actions = [(C, D), (C, D), (C, D), (C, D), (C, D), (D, D), (C, D), + (C, D), (D, D), (C, D), (D, D), (C, C)] + actions += [(C, C)] * 99 + self.versus_test(changed_man, expected_actions=actions, seed=1) diff --git a/docs/reference/overview_of_strategies.rst b/docs/reference/overview_of_strategies.rst index cca713f89..15430e9d7 100644 --- a/docs/reference/overview_of_strategies.rst +++ b/docs/reference/overview_of_strategies.rst @@ -114,7 +114,7 @@ repository. "K41R_", "Herb Weiner", "Not Implemented" "K42R_", "Otto Borufsen", ":class:`Borufsen `" "K43R_", "R D Anderson", "Not Implemented" - "K44R_", "William Adams", "Not Implemented" + "K44R_", "William Adams", ":class:`WmAdams `" "K45R_", "Michael F McGurrin", "Not Implemented" "K46R_", "Graham J Eatherley", ":class:`Eatherley `" "K47R_", "Richard Hufford", "Not Implemented" diff --git a/docs/tutorials/advanced/classification_of_strategies.rst b/docs/tutorials/advanced/classification_of_strategies.rst index 33dd7bb77..79789e31f 100644 --- a/docs/tutorials/advanced/classification_of_strategies.rst +++ b/docs/tutorials/advanced/classification_of_strategies.rst @@ -47,7 +47,7 @@ strategies:: ... } >>> strategies = axl.filtered_strategies(filterset) >>> len(strategies) - 77 + 78 Or, to find out how many strategies only use 1 turn worth of memory to make a decision::