From d447b0b89305a96b80b347c99df75a38b13c0ebc Mon Sep 17 00:00:00 2001 From: E Shaw Date: Wed, 22 Mar 2017 13:31:03 +0800 Subject: [PATCH 1/8] total refactor --- axelrod/strategies/backstabber.py | 56 ++++++++++------- axelrod/tests/strategies/test_backstabber.py | 65 ++++++++++++-------- 2 files changed, 76 insertions(+), 45 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index b6b892f8a..b86580254 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -17,23 +17,18 @@ class BackStabber(Player): classifier = { 'memory_depth': float('inf'), 'stochastic': False, - 'makes_use_of': set(['length']), + 'makes_use_of': {'length'}, 'long_run_time': False, 'inspects_source': False, 'manipulates_source': False, 'manipulates_state': False } - @staticmethod - def strategy(opponent: Player) -> Action: - if not opponent.history: - return C - if opponent.defections > 3: - return D - return C + def strategy(self, opponent: Player) -> Action: + return _backstabber_strategy(opponent) -@FinalTransformer((D, D), name_prefix=None) # End with two defections +@FinalTransformer((D, D), name_prefix=None) # End with two defections class DoubleCrosser(Player): """ Forgives the first 3 defections but on the fourth @@ -46,7 +41,7 @@ class DoubleCrosser(Player): classifier = { 'memory_depth': float('inf'), 'stochastic': False, - 'makes_use_of': set(['length']), + 'makes_use_of': {'length'}, 'long_run_time': False, 'inspects_source': False, 'manipulates_source': False, @@ -54,15 +49,34 @@ class DoubleCrosser(Player): } def strategy(self, opponent: Player) -> Action: - cutoff = 6 - - if not opponent.history: - return C - if len(opponent.history) < 180: - if len(opponent.history) > cutoff: - if D not in opponent.history[:cutoff + 1]: - if opponent.history[-2:] != [D, D]: # Fail safe - return C - if opponent.defections > 3: - return D + if self._opponent_triggers_alt_strategy(opponent): + return _alt_strategy(opponent) + return _backstabber_strategy(opponent) + + def _opponent_triggers_alt_strategy(self, opponent): + before_alt_strategy = 6 + alt_strategy_final_round = 180 + if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): + return False + current_plays = len(self.history) + return before_alt_strategy < current_plays <= alt_strategy_final_round + + +def _backstabber_strategy(opponent): + if not opponent.history: return C + if opponent.defections > 3: + return D + return C + + +def _alt_strategy(opponent): + final_two_plays = opponent.history[-2:] + if final_two_plays == [D, D]: + return D + return C + + +def _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): + return D in opponent.history[:first_n_rounds] + diff --git a/axelrod/tests/strategies/test_backstabber.py b/axelrod/tests/strategies/test_backstabber.py index 52e4b35ea..66fe4fe69 100644 --- a/axelrod/tests/strategies/test_backstabber.py +++ b/axelrod/tests/strategies/test_backstabber.py @@ -12,7 +12,7 @@ class TestBackStabber(TestPlayer): expected_classifier = { 'memory_depth': float('inf'), 'stochastic': False, - 'makes_use_of': set(['length']), + 'makes_use_of': {'length'}, 'long_run_time': False, 'inspects_source': False, 'manipulates_source': False, @@ -24,31 +24,40 @@ def test_strategy(self): Forgives the first 3 defections but on the fourth will defect forever. Defects after the 198th round unconditionally. """ + self._defects_after_four_defections() + self._defects_on_last_two_rounds_by_match_len() + def _defects_after_four_defections(self): self.first_play_test(C) - # Forgives three defections - self.responses_test([C], [C], [D], length=200) - self.responses_test([C], [C, C], [D, D], length=200) - self.responses_test([C], [C, C, C], [D, D, D], length=200) - self.responses_test([D], [C, C, C, C], [D, D, D, D], length=200) + defector_actions = [(C, D), (C, D), (C, D), (C, D), (D, D), (D, D)] + self.versus_test(axelrod.Defector(), expected_actions=defector_actions, match_attributes={"length": 200}) + alternator_actions = [(C, C), (C, D)] * 4 + [(D, C), (D, D)] * 2 + self.versus_test(axelrod.Alternator(), expected_actions=alternator_actions, match_attributes={"length": 200}) + + def _defects_on_last_two_rounds_by_match_len(self): + actions = [(C, C)] * 198 + [(D, C), (D, C)] + self.versus_test(axelrod.Cooperator(), expected_actions=actions, match_attributes={"length": 200}) + + actions = [(C, C)] * 10 + [(D, C), (D, C)] + self.versus_test(axelrod.Cooperator(), expected_actions=actions, match_attributes={"length": 12}) - # Defects on rounds 199, and 200 no matter what - self.responses_test([C, D, D], [C] * 197, [C] * 197, length=200) # Test that exceeds tournament length - self.responses_test([D, D, C], [C] * 198, [C] * 198, length=200) + actions = [(C, C)] * 198 + [(D, C), (D, C), (C, C), (C, C)] + self.versus_test(axelrod.Cooperator(), expected_actions=actions, match_attributes={"length": 200}) # But only if the tournament is known - self.responses_test([C, C, C], [C] * 198, [C] * 198, length=-1) + actions = [(C, C)] * 202 + self.versus_test(axelrod.Cooperator(), expected_actions=actions, match_attributes={"length": -1}) -class TestDoubleCrosser(TestPlayer): +class TestDoubleCrosser(TestBackStabber): name = "DoubleCrosser" player = axelrod.DoubleCrosser expected_classifier = { 'memory_depth': float('inf'), 'stochastic': False, - 'makes_use_of': set(['length']), + 'makes_use_of': {'length'}, 'long_run_time': False, 'inspects_source': False, 'manipulates_source': False, @@ -63,19 +72,27 @@ def test_strategy(self): cooperate until the 180th round. Defects after the 198th round unconditionally. """ - self.first_play_test(C) - # Forgives three defections - self.responses_test([C], [C], [D], length=200) - self.responses_test([C], [C, C], [D, D], length=200) - self.responses_test([C], [C, C, C], [D, D, D], length=200) - self.responses_test([D], [C, C, C, C], [D, D, D, D], length=200) + self.special_case_strategy() + super(TestDoubleCrosser, self).test_strategy() + + def special_case_strategy(self): + + """ + 6 * [C] + 2 * [D] -> D + 6 * [C] + 20* [D] -> D + 6 * [C] + 2 * [D] + [C] - > C + 6 * [C] + 20 * [D] + [C] - > C + """ + starting_cooperation = 6 * [C] + starting_rounds_with_c = 6 * [(C, C)] + + starting_defection = [D] + 5 * [C] + starting_rounds_with_d = [(D, D)] + 5 * [(C, C)] - # If opponent did not defect in the first six rounds, cooperate until - # round 180 - self.responses_test([C] * 174, [C] * 6, [C] * 6, length=200) - self.responses_test([C] * 160, [C] * 12, [C] * 6 + [D] + [C] * 5, - length=200) + opponent_actions = starting_cooperation + [D, D, C] + expected_actions = starting_rounds_with_c + [(C, D), (C, D), (D, C)] + self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, + match_attributes={"length": 200}) # Defects on rounds 199, and 200 no matter what - self.responses_test([C, D, D], [C] * 197, [C] * 197, length=200) From ea05b78e0849a8724bf999989123237cd220e9e6 Mon Sep 17 00:00:00 2001 From: E Shaw Date: Wed, 22 Mar 2017 17:55:01 +0800 Subject: [PATCH 2/8] total refactor --- axelrod/strategies/backstabber.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index b86580254..bf04d2fa7 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -49,18 +49,10 @@ class DoubleCrosser(Player): } def strategy(self, opponent: Player) -> Action: - if self._opponent_triggers_alt_strategy(opponent): + if _opponent_triggers_alt_strategy(opponent): return _alt_strategy(opponent) return _backstabber_strategy(opponent) - def _opponent_triggers_alt_strategy(self, opponent): - before_alt_strategy = 6 - alt_strategy_final_round = 180 - if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): - return False - current_plays = len(self.history) - return before_alt_strategy < current_plays <= alt_strategy_final_round - def _backstabber_strategy(opponent): if not opponent.history: @@ -77,6 +69,15 @@ def _alt_strategy(opponent): return C +def _opponent_triggers_alt_strategy(opponent): + before_alt_strategy = 6 + alt_strategy_final_round = 180 + if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): + return False + rounds_opponent_played = len(opponent.history) + return before_alt_strategy < rounds_opponent_played <= alt_strategy_final_round + + def _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): return D in opponent.history[:first_n_rounds] From 8385eef12588e37bac164d69e8182699fc8d811e Mon Sep 17 00:00:00 2001 From: E Shaw Date: Wed, 22 Mar 2017 21:42:38 +0800 Subject: [PATCH 3/8] more thorough test --- axelrod/strategies/backstabber.py | 12 ++-- axelrod/tests/strategies/test_backstabber.py | 65 ++++++++++++++------ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index bf04d2fa7..cdcdac6d7 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -32,9 +32,11 @@ def strategy(self, opponent: Player) -> Action: class DoubleCrosser(Player): """ Forgives the first 3 defections but on the fourth - will defect forever. If the opponent did not defect - in the first 6 rounds the player will cooperate until - the 180th round. Defects on the last 2 rounds unconditionally. + will defect forever. Defects on the last 2 rounds unconditionally. + + From rounds 7 through 179, + if the opponent did not defect in the first 6 rounds, + the player will only defect after the opponent has defected twice in-a-row. """ name = 'DoubleCrosser' @@ -71,11 +73,11 @@ def _alt_strategy(opponent): def _opponent_triggers_alt_strategy(opponent): before_alt_strategy = 6 - alt_strategy_final_round = 180 + after_alt_strategy = 180 if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): return False rounds_opponent_played = len(opponent.history) - return before_alt_strategy < rounds_opponent_played <= alt_strategy_final_round + return before_alt_strategy < rounds_opponent_played < after_alt_strategy def _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): diff --git a/axelrod/tests/strategies/test_backstabber.py b/axelrod/tests/strategies/test_backstabber.py index 66fe4fe69..154fb5a3d 100644 --- a/axelrod/tests/strategies/test_backstabber.py +++ b/axelrod/tests/strategies/test_backstabber.py @@ -65,34 +65,59 @@ class TestDoubleCrosser(TestBackStabber): } def test_strategy(self): - """ - Forgives the first 3 defections but on the fourth will defect forever. - If the opponent did not defect in the first 6 rounds the player will - cooperate until the 180th round. Defects after the 198th round - unconditionally. + Forgives the first 3 defections but on the fourth + will defect forever. Defects on the last 2 rounds unconditionally. + + If the opponent did not defect + in the first 6 rounds,until the 180th round, the player will only defect + after the opponent has defected twice in-a-row. """ - self.special_case_strategy() + self._when_alt_strategy_is_triggered() + self._starting_defect_keeps_alt_strategy_from_triggering() + self._alt_strategy_stops_at_round_180() super(TestDoubleCrosser, self).test_strategy() - def special_case_strategy(self): + def _when_alt_strategy_is_triggered(self): + starting_cooperation = [C] * 6 + starting_rounds = [(C, C)] * 6 - """ - 6 * [C] + 2 * [D] -> D - 6 * [C] + 20* [D] -> D - 6 * [C] + 2 * [D] + [C] - > C - 6 * [C] + 20 * [D] + [C] - > C - """ - starting_cooperation = 6 * [C] - starting_rounds_with_c = 6 * [(C, C)] + opponent_actions = starting_cooperation + [D, D, C, D] + expected_actions = starting_rounds + [(C, D), (C, D), (D, C), (C, D)] + self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, + match_attributes={"length": 200}) + + opponent_actions = starting_cooperation + [D, D, D, D, C, D] + expected_actions = starting_rounds + [(C, D), (C, D), (D, D), (D, D), (D, C), (C, D)] + self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, + match_attributes={"length": 200}) + + def _starting_defect_keeps_alt_strategy_from_triggering(self): + opponent_actions_suffix = [C, D, C, D, D] + 3 * [C] + expected_actions_suffix = [(C, C), (C, D), (C, C), (C, D), (C, D)] + 3 * [(D, C)] + + defects_on_first = [D] + [C] * 5 + defects_on_first_actions = [(C, D)] + [(C, C)] * 5 + self.versus_test(axelrod.MockPlayer(defects_on_first + opponent_actions_suffix), + expected_actions=defects_on_first_actions + expected_actions_suffix, + match_attributes={"length": 200}) + + defects_in_middle = [C, C, D, C, C, C] + defects_in_middle_actions = [(C, C), (C, C), (C, D), (C, C), (C, C), (C, C)] + self.versus_test(axelrod.MockPlayer(defects_in_middle + opponent_actions_suffix), + expected_actions=defects_in_middle_actions + expected_actions_suffix, + match_attributes={"length": 200}) - starting_defection = [D] + 5 * [C] - starting_rounds_with_d = [(D, D)] + 5 * [(C, C)] + defects_on_last = [C] * 5 + [D] + defects_on_last_actions = [(C, C)] * 5 + [(C, D)] + self.versus_test(axelrod.MockPlayer(defects_on_last + opponent_actions_suffix), + expected_actions=defects_on_last_actions + expected_actions_suffix, + match_attributes={"length": 200}) - opponent_actions = starting_cooperation + [D, D, C] - expected_actions = starting_rounds_with_c + [(C, D), (C, D), (D, C)] + def _alt_strategy_stops_at_round_180(self): + opponent_actions = [C] * 6 + [C, D] * 87 + [C] * 6 + expected_actions = [(C, C)] * 6 + [(C, C), (C, D)] * 87 + [(D, C)] * 6 self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, match_attributes={"length": 200}) - # Defects on rounds 199, and 200 no matter what From 54c4099652cf6d97d4e83bf4c08910d1d4b3ebcd Mon Sep 17 00:00:00 2001 From: E Shaw Date: Thu, 23 Mar 2017 00:57:14 +0800 Subject: [PATCH 4/8] made suggested changes --- axelrod/strategies/backstabber.py | 21 ++++++++--- axelrod/tests/strategies/test_backstabber.py | 39 ++++++-------------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index cdcdac6d7..00822b5dd 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -56,7 +56,10 @@ def strategy(self, opponent: Player) -> Action: return _backstabber_strategy(opponent) -def _backstabber_strategy(opponent): +def _backstabber_strategy(opponent: Player) -> Action: + """ + Cooperates until opponent defects a total of four times, then always defects. + """ if not opponent.history: return C if opponent.defections > 3: @@ -64,14 +67,20 @@ def _backstabber_strategy(opponent): return C -def _alt_strategy(opponent): +def _alt_strategy(opponent: Player) -> Action: + """ + If opponent's last two plays were defect, then defects on next round. Otherwise, cooperates. + """ final_two_plays = opponent.history[-2:] if final_two_plays == [D, D]: return D return C -def _opponent_triggers_alt_strategy(opponent): +def _opponent_triggers_alt_strategy(opponent: Player) -> bool: + """ + If opponent did not defect in first 6 rounds and the round is from 7 to 179, return True. Else, return False. + """ before_alt_strategy = 6 after_alt_strategy = 180 if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): @@ -80,6 +89,8 @@ def _opponent_triggers_alt_strategy(opponent): return before_alt_strategy < rounds_opponent_played < after_alt_strategy -def _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): +def _opponent_defected_in_first_n_rounds(opponent: Player, first_n_rounds: int) -> bool: + """ + If opponent defected in the first N rounds, return True. Else return False. + """ return D in opponent.history[:first_n_rounds] - diff --git a/axelrod/tests/strategies/test_backstabber.py b/axelrod/tests/strategies/test_backstabber.py index 154fb5a3d..8274c9a70 100644 --- a/axelrod/tests/strategies/test_backstabber.py +++ b/axelrod/tests/strategies/test_backstabber.py @@ -19,15 +19,7 @@ class TestBackStabber(TestPlayer): 'manipulates_state': False } - def test_strategy(self): - """ - Forgives the first 3 defections but on the fourth - will defect forever. Defects after the 198th round unconditionally. - """ - self._defects_after_four_defections() - self._defects_on_last_two_rounds_by_match_len() - - def _defects_after_four_defections(self): + def test_defects_after_four_defections(self): self.first_play_test(C) # Forgives three defections defector_actions = [(C, D), (C, D), (C, D), (C, D), (D, D), (D, D)] @@ -35,7 +27,7 @@ def _defects_after_four_defections(self): alternator_actions = [(C, C), (C, D)] * 4 + [(D, C), (D, D)] * 2 self.versus_test(axelrod.Alternator(), expected_actions=alternator_actions, match_attributes={"length": 200}) - def _defects_on_last_two_rounds_by_match_len(self): + def test_defects_on_last_two_rounds_by_match_len(self): actions = [(C, C)] * 198 + [(D, C), (D, C)] self.versus_test(axelrod.Cooperator(), expected_actions=actions, match_attributes={"length": 200}) @@ -51,7 +43,11 @@ def _defects_on_last_two_rounds_by_match_len(self): class TestDoubleCrosser(TestBackStabber): - + """ + Behaves like BackStabber except when its alternate strategy is triggered. + The alternate strategy is triggered when opponent did not defect in the first 6 rounds, and + 6 < the current round < 180. + """ name = "DoubleCrosser" player = axelrod.DoubleCrosser expected_classifier = { @@ -64,22 +60,10 @@ class TestDoubleCrosser(TestBackStabber): 'manipulates_state': False } - def test_strategy(self): + def test_when_alt_strategy_is_triggered(self): """ - Forgives the first 3 defections but on the fourth - will defect forever. Defects on the last 2 rounds unconditionally. - - If the opponent did not defect - in the first 6 rounds,until the 180th round, the player will only defect - after the opponent has defected twice in-a-row. + The alternate strategy is if opponent's last two plays were defect, then defect. Otherwise, cooperate. """ - - self._when_alt_strategy_is_triggered() - self._starting_defect_keeps_alt_strategy_from_triggering() - self._alt_strategy_stops_at_round_180() - super(TestDoubleCrosser, self).test_strategy() - - def _when_alt_strategy_is_triggered(self): starting_cooperation = [C] * 6 starting_rounds = [(C, C)] * 6 @@ -93,7 +77,7 @@ def _when_alt_strategy_is_triggered(self): self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, match_attributes={"length": 200}) - def _starting_defect_keeps_alt_strategy_from_triggering(self): + def test_starting_defect_keeps_alt_strategy_from_triggering(self): opponent_actions_suffix = [C, D, C, D, D] + 3 * [C] expected_actions_suffix = [(C, C), (C, D), (C, C), (C, D), (C, D)] + 3 * [(D, C)] @@ -115,9 +99,8 @@ def _starting_defect_keeps_alt_strategy_from_triggering(self): expected_actions=defects_on_last_actions + expected_actions_suffix, match_attributes={"length": 200}) - def _alt_strategy_stops_at_round_180(self): + def test_alt_strategy_stops_at_round_180(self): opponent_actions = [C] * 6 + [C, D] * 87 + [C] * 6 expected_actions = [(C, C)] * 6 + [(C, C), (C, D)] * 87 + [(D, C)] * 6 self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, match_attributes={"length": 200}) - From f3942476092697502e93d0173e0f72244af7dfb8 Mon Sep 17 00:00:00 2001 From: E Shaw Date: Thu, 23 Mar 2017 02:28:40 +0800 Subject: [PATCH 5/8] rewrote alt_strategy trigger test. and tests --- axelrod/strategies/backstabber.py | 18 +++++++------ axelrod/tests/strategies/test_backstabber.py | 28 +++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index 00822b5dd..bf73a4300 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -34,8 +34,8 @@ class DoubleCrosser(Player): Forgives the first 3 defections but on the fourth will defect forever. Defects on the last 2 rounds unconditionally. - From rounds 7 through 179, - if the opponent did not defect in the first 6 rounds, + If 8 <= current round <= 180, + if the opponent did not defect in the first 7 rounds, the player will only defect after the opponent has defected twice in-a-row. """ @@ -79,14 +79,16 @@ def _alt_strategy(opponent: Player) -> Action: def _opponent_triggers_alt_strategy(opponent: Player) -> bool: """ - If opponent did not defect in first 6 rounds and the round is from 7 to 179, return True. Else, return False. + If opponent did not defect in first 7 rounds and the current round is from 8 to 180, return True. + Else, return False. """ - before_alt_strategy = 6 - after_alt_strategy = 180 - if _opponent_defected_in_first_n_rounds(opponent, before_alt_strategy): + before_alt_strategy = 7 + last_round_of_alt_strategy = 180 + required_rounds_of_opponent_cooperation = before_alt_strategy + if _opponent_defected_in_first_n_rounds(opponent, required_rounds_of_opponent_cooperation): return False - rounds_opponent_played = len(opponent.history) - return before_alt_strategy < rounds_opponent_played < after_alt_strategy + current_round = len(opponent.history) + 1 + return before_alt_strategy < current_round <= last_round_of_alt_strategy def _opponent_defected_in_first_n_rounds(opponent: Player, first_n_rounds: int) -> bool: diff --git a/axelrod/tests/strategies/test_backstabber.py b/axelrod/tests/strategies/test_backstabber.py index 8274c9a70..9a1c2f792 100644 --- a/axelrod/tests/strategies/test_backstabber.py +++ b/axelrod/tests/strategies/test_backstabber.py @@ -45,8 +45,8 @@ def test_defects_on_last_two_rounds_by_match_len(self): class TestDoubleCrosser(TestBackStabber): """ Behaves like BackStabber except when its alternate strategy is triggered. - The alternate strategy is triggered when opponent did not defect in the first 6 rounds, and - 6 < the current round < 180. + The alternate strategy is triggered when opponent did not defect in the first 7 rounds, and + 8 <= the current round <= 180. """ name = "DoubleCrosser" player = axelrod.DoubleCrosser @@ -64,8 +64,8 @@ def test_when_alt_strategy_is_triggered(self): """ The alternate strategy is if opponent's last two plays were defect, then defect. Otherwise, cooperate. """ - starting_cooperation = [C] * 6 - starting_rounds = [(C, C)] * 6 + starting_cooperation = [C] * 7 + starting_rounds = [(C, C)] * 7 opponent_actions = starting_cooperation + [D, D, C, D] expected_actions = starting_rounds + [(C, D), (C, D), (D, C), (C, D)] @@ -81,26 +81,28 @@ def test_starting_defect_keeps_alt_strategy_from_triggering(self): opponent_actions_suffix = [C, D, C, D, D] + 3 * [C] expected_actions_suffix = [(C, C), (C, D), (C, C), (C, D), (C, D)] + 3 * [(D, C)] - defects_on_first = [D] + [C] * 5 - defects_on_first_actions = [(C, D)] + [(C, C)] * 5 + defects_on_first = [D] + [C] * 6 + defects_on_first_actions = [(C, D)] + [(C, C)] * 6 self.versus_test(axelrod.MockPlayer(defects_on_first + opponent_actions_suffix), expected_actions=defects_on_first_actions + expected_actions_suffix, match_attributes={"length": 200}) - defects_in_middle = [C, C, D, C, C, C] - defects_in_middle_actions = [(C, C), (C, C), (C, D), (C, C), (C, C), (C, C)] + defects_in_middle = [C, C, C, D, C, C, C] + defects_in_middle_actions = [(C, C), (C, C), (C, C), (C, D), (C, C), (C, C), (C, C)] self.versus_test(axelrod.MockPlayer(defects_in_middle + opponent_actions_suffix), expected_actions=defects_in_middle_actions + expected_actions_suffix, match_attributes={"length": 200}) - defects_on_last = [C] * 5 + [D] - defects_on_last_actions = [(C, C)] * 5 + [(C, D)] + defects_on_last = [C] * 6 + [D] + defects_on_last_actions = [(C, C)] * 6 + [(C, D)] self.versus_test(axelrod.MockPlayer(defects_on_last + opponent_actions_suffix), expected_actions=defects_on_last_actions + expected_actions_suffix, match_attributes={"length": 200}) - def test_alt_strategy_stops_at_round_180(self): - opponent_actions = [C] * 6 + [C, D] * 87 + [C] * 6 - expected_actions = [(C, C)] * 6 + [(C, C), (C, D)] * 87 + [(D, C)] * 6 + def test_alt_strategy_stops_after_round_180(self): + one_eighty_opponent_actions = [C] * 8 + [C, D] * 86 + one_eighty_expected_actions = [(C, C)] * 8 + [(C, C), (C, D)] * 86 + opponent_actions = one_eighty_opponent_actions + [C] * 6 + expected_actions = one_eighty_expected_actions + [(D, C)] * 6 self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, match_attributes={"length": 200}) From a240da100d2e5dac283905bec78962cd998ab114 Mon Sep 17 00:00:00 2001 From: E Shaw Date: Thu, 23 Mar 2017 12:46:46 +0800 Subject: [PATCH 6/8] little change --- axelrod/strategies/backstabber.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index bf73a4300..80448b2cc 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -82,10 +82,9 @@ def _opponent_triggers_alt_strategy(opponent: Player) -> bool: If opponent did not defect in first 7 rounds and the current round is from 8 to 180, return True. Else, return False. """ - before_alt_strategy = 7 + before_alt_strategy = first_n_rounds = 7 last_round_of_alt_strategy = 180 - required_rounds_of_opponent_cooperation = before_alt_strategy - if _opponent_defected_in_first_n_rounds(opponent, required_rounds_of_opponent_cooperation): + if _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): return False current_round = len(opponent.history) + 1 return before_alt_strategy < current_round <= last_round_of_alt_strategy From 3d3a27c6990899683b52d687ef5d6a0b764afdca Mon Sep 17 00:00:00 2001 From: E Shaw Date: Thu, 23 Mar 2017 22:10:52 +0800 Subject: [PATCH 7/8] unittests for module methods --- axelrod/tests/strategies/test_backstabber.py | 95 ++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/axelrod/tests/strategies/test_backstabber.py b/axelrod/tests/strategies/test_backstabber.py index 9a1c2f792..2a16f4c9a 100644 --- a/axelrod/tests/strategies/test_backstabber.py +++ b/axelrod/tests/strategies/test_backstabber.py @@ -1,5 +1,9 @@ """Tests for BackStabber and DoubleCrosser.""" import axelrod +import unittest + +from axelrod.strategies import backstabber +from axelrod.mock_player import Player, update_history from .test_player import TestPlayer C, D = axelrod.Actions.C, axelrod.Actions.D @@ -106,3 +110,94 @@ def test_alt_strategy_stops_after_round_180(self): expected_actions = one_eighty_expected_actions + [(D, C)] * 6 self.versus_test(axelrod.MockPlayer(opponent_actions), expected_actions=expected_actions, match_attributes={"length": 200}) + + +class TestModuleMethods(unittest.TestCase): + + def setUp(self): + self.player = Player() + + def update_history(self, history_list): + for move in history_list: + update_history(self.player, move) + + def test_update_history(self): + self.assertEqual(self.player.history, []) + self.assertEqual(self.player.defections, 0) + + self.update_history([D, D, C]) + + self.assertEqual(self.player.history, [D, D, C]) + self.assertEqual(self.player.defections, 2) + + self.player.reset() + self.update_history([D]) + self.assertEqual(self.player.history, [D]) + self.assertEqual(self.player.defections, 1) + + def test_backstabber_strategy_no_history(self): + self.assertEqual(C, backstabber._backstabber_strategy(self.player)) + + def test_backstabber_strategy_three_defections(self): + self.update_history([D, D, D]) + self.assertEqual(C, backstabber._backstabber_strategy(self.player)) + + def test_backstabber_strategy_four_defections(self): + self.update_history([D, D, D, D]) + self.assertEqual(D, backstabber._backstabber_strategy(self.player)) + + def test_alt_strategy_no_history_one_history_returns_C(self): + self.assertEqual(C, backstabber._alt_strategy(self.player)) + + self.update_history([D]) + self.assertEqual(C, backstabber._alt_strategy(self.player)) + + def test_alt_strategy_returns_D(self): + self.update_history([C, C, D, D]) + self.assertEqual(D, backstabber._alt_strategy(self.player)) + + self.player.reset() + self.update_history([D, D, D]) + self.assertEqual(D, backstabber._alt_strategy(self.player)) + + def test_alt_strategy_returns_C(self): + self.update_history([D, D, D, C]) + self.assertEqual(C, backstabber._alt_strategy(self.player)) + + def test_opponent_defected_in_first_n_rounds(self): + self.update_history([C, C, C, C, D, C]) + self.assertTrue(backstabber._opponent_defected_in_first_n_rounds(self.player, 10)) + self.assertTrue(backstabber._opponent_defected_in_first_n_rounds(self.player, 6)) + self.assertTrue(backstabber._opponent_defected_in_first_n_rounds(self.player, 5)) + + self.assertFalse(backstabber._opponent_defected_in_first_n_rounds(self.player, 4)) + + def test_opponent_triggers_alt_strategy_false_by_defected_in_first_n_rounds(self): + last_of_first_n_rounds = 7 + history = [C if rnd != last_of_first_n_rounds else D for rnd in range(1, 20)] + self.update_history(history) + self.assertFalse(backstabber._opponent_triggers_alt_strategy(self.player)) + + def test_opponent_triggers_alt_strategy_false_by_before_round_eight(self): + current_round = 7 + history = [C] * (current_round - 1) + self.update_history(history) + self.assertFalse(backstabber._opponent_triggers_alt_strategy(self.player)) + + def test_opponent_triggers_alt_strategy_false_by_after_round_one_eighty(self): + current_round = 181 + history = [C] * (current_round - 1) + self.update_history(history) + self.assertFalse(backstabber._opponent_triggers_alt_strategy(self.player)) + + def test_opponent_triggers_alt_strategy_true_edge_case_high(self): + current_round = 180 + history = [C] * (current_round - 1) + self.update_history(history) + self.assertTrue(backstabber._opponent_triggers_alt_strategy(self.player)) + + def test_opponent_triggers_alt_strategy_true_edge_case_low(self): + current_round = 8 + history = [C] * (current_round - 1) + self.update_history(history) + self.assertTrue(backstabber._opponent_triggers_alt_strategy(self.player)) From 5d741540ed52df476ed79d046bdbbfcdc511fed7 Mon Sep 17 00:00:00 2001 From: E Shaw Date: Fri, 24 Mar 2017 00:57:53 +0800 Subject: [PATCH 8/8] last_two to previous_two --- axelrod/strategies/backstabber.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/axelrod/strategies/backstabber.py b/axelrod/strategies/backstabber.py index 80448b2cc..7c60f707e 100644 --- a/axelrod/strategies/backstabber.py +++ b/axelrod/strategies/backstabber.py @@ -69,10 +69,10 @@ def _backstabber_strategy(opponent: Player) -> Action: def _alt_strategy(opponent: Player) -> Action: """ - If opponent's last two plays were defect, then defects on next round. Otherwise, cooperates. + If opponent's previous two plays were defect, then defects on next round. Otherwise, cooperates. """ - final_two_plays = opponent.history[-2:] - if final_two_plays == [D, D]: + previous_two_plays = opponent.history[-2:] + if previous_two_plays == [D, D]: return D return C