Skip to content

Commit 1fa74da

Browse files
authored
Merge pull request #786 from varung97/master
Add BetterAndBetter, WorseAndWorse2 and WorseAndWorse3 Strategies
2 parents 5c12de6 + b26142c commit 1fa74da

File tree

7 files changed

+209
-7
lines changed

7 files changed

+209
-7
lines changed

axelrod/strategies/_strategies.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Joss, Shubik, Tullock, UnnamedStrategy)
1111
from .axelrod_second import Champion, Eatherley, Tester
1212
from .backstabber import BackStabber, DoubleCrosser
13+
from .better_and_better import BetterAndBetter
1314
from .calculator import Calculator
1415
from .cooperator import Cooperator, TrickyCooperator
1516
from .cycler import (
@@ -63,7 +64,7 @@
6364
TitForTat, TitFor2Tats, TwoTitsForTat, Bully, SneakyTitForTat,
6465
SuspiciousTitForTat, AntiTitForTat, HardTitForTat, HardTitFor2Tats,
6566
OmegaTFT, Gradual, ContriteTitForTat, SlowTitForTwoTats, AdaptiveTitForTat,SpitefulTitForTat)
66-
from .worse_and_worse import (WorseAndWorse, KnowledgeableWorseAndWorse)
67+
from .worse_and_worse import (WorseAndWorse, KnowledgeableWorseAndWorse, WorseAndWorse2, WorseAndWorse3)
6768

6869
# Note: Meta* strategies are handled in .__init__.py
6970

@@ -81,6 +82,7 @@
8182
Appeaser,
8283
ArrogantQLearner,
8384
AverageCopier,
85+
BetterAndBetter,
8486
BackStabber,
8587
Bully,
8688
Calculator,
@@ -208,6 +210,8 @@
208210
WinShiftLoseStay,
209211
WinStayLoseShift,
210212
WorseAndWorse,
213+
WorseAndWorse2,
214+
WorseAndWorse3,
211215
ZDExtort2,
212216
ZDExtort2v2,
213217
ZDExtort4,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from axelrod import Actions, Player, random_choice
2+
3+
C, D = Actions.C, Actions.D
4+
5+
class BetterAndBetter(Player):
6+
"""
7+
Defects with probability of '(1000 - current turn) / 1000'.
8+
Therefore it is less and less likely to defect as the round goes on.
9+
10+
Names:
11+
- Better and Better: [PRISON1998]_
12+
13+
"""
14+
15+
name = 'Better and Better'
16+
classifier = {
17+
'memory_depth': float('inf'),
18+
'stochastic': True,
19+
'makes_use_of': set(),
20+
'long_run_time': False,
21+
'inspects_source': False,
22+
'manipulates_source': False,
23+
'manipulates_state': False
24+
}
25+
26+
def strategy(self, opponent):
27+
current_round = len(self.history) + 1
28+
probability = current_round / 1000
29+
return random_choice(probability)

axelrod/strategies/worse_and_worse.py

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
C, D = Actions.C, Actions.D
44

5-
class WorseAndWorse (Player):
5+
class WorseAndWorse(Player):
66
"""
77
Defects with probability of 'current turn / 1000'. Therefore
88
it is more and more likely to defect as the round goes on.
@@ -28,11 +28,11 @@ class WorseAndWorse (Player):
2828

2929
def strategy(self, opponent):
3030
current_round = len(self.history) + 1
31-
probability = 1 - float(current_round) / 1000
31+
probability = 1 - current_round / 1000
3232
return random_choice(probability)
3333

3434

35-
class KnowledgeableWorseAndWorse (Player):
35+
class KnowledgeableWorseAndWorse(Player):
3636
"""
3737
This strategy is based on 'Worse And Worse' but will defect with probability
3838
of 'current turn / total no. of turns'.
@@ -55,5 +55,74 @@ class KnowledgeableWorseAndWorse (Player):
5555
def strategy(self, opponent):
5656
current_round = len(self.history) + 1
5757
expected_length = self.match_attributes['length']
58-
probability = 1 - float(current_round) / expected_length
58+
probability = 1 - current_round / expected_length
5959
return random_choice(probability)
60+
61+
62+
class WorseAndWorse2(Player):
63+
"""
64+
65+
Plays as tit for tat during the first 20 moves.
66+
Then defects with probability (current turn - 20) / current turn.
67+
Therefore it is more and more likely to defect as the round goes on.
68+
69+
Names:
70+
- Worse and Worse 2: [PRISON1998]_
71+
72+
"""
73+
74+
name = 'Worse and Worse 2'
75+
classifier = {
76+
'memory_depth': float('inf'),
77+
'stochastic': True,
78+
'makes_use_of': set(),
79+
'long_run_time': False,
80+
'inspects_source': False,
81+
'manipulates_source': False,
82+
'manipulates_state': False
83+
}
84+
85+
def strategy(self, opponent):
86+
current_round = len(self.history) + 1
87+
88+
if current_round == 1:
89+
return C
90+
elif current_round <= 20:
91+
return opponent.history[-1]
92+
else:
93+
probability = 20 / current_round
94+
return random_choice(probability)
95+
96+
97+
class WorseAndWorse3(Player):
98+
"""
99+
100+
Cooperates in the first turn.
101+
Then defects with probability no. of opponent defects / (current turn - 1).
102+
Therefore it is more likely to defect when the opponent defects for a larger
103+
proportion of the turns.
104+
105+
Names:
106+
- Worse and Worse 3: [PRISON1998]_
107+
108+
"""
109+
110+
name = 'Worse and Worse 3'
111+
classifier = {
112+
'memory_depth': float('inf'),
113+
'stochastic': True,
114+
'makes_use_of': set(),
115+
'long_run_time': False,
116+
'inspects_source': False,
117+
'manipulates_source': False,
118+
'manipulates_state': False
119+
}
120+
121+
def strategy(self, opponent):
122+
current_round = len(self.history) + 1
123+
124+
if current_round == 1:
125+
return C
126+
else:
127+
probability = 1 - opponent.defections / (current_round - 1)
128+
return random_choice(probability)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Test for the Better and Better strategy."""
2+
3+
import axelrod
4+
5+
from .test_player import TestPlayer
6+
7+
C, D = axelrod.Actions.C, axelrod.Actions.D
8+
9+
class TestBetterAndBetter(TestPlayer):
10+
11+
name = "Better and Better"
12+
player = axelrod.BetterAndBetter
13+
expected_classifier = {
14+
'memory_depth': float('inf'),
15+
'stochastic': True,
16+
'makes_use_of': set(),
17+
'long_run_time': False,
18+
'inspects_source': False,
19+
'manipulates_source': False,
20+
'manipulates_state': False
21+
}
22+
23+
def test_strategy(self):
24+
"""
25+
Test that the strategy gives expected behaviour
26+
"""
27+
28+
self.responses_test([], [], [D, D, D, D, C, D, D, D, D, D], random_seed=6)
29+
self.responses_test([], [], [D, D, D, D, D, D, D, D, D, D], random_seed=8)

axelrod/tests/unit/test_worse_and_worse.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import axelrod
44

5-
from .test_player import TestPlayer
5+
from .test_player import TestPlayer, TestHeadsUp
66

77
C, D = axelrod.Actions.C, axelrod.Actions.D
88

@@ -105,3 +105,71 @@ def test_strategy(self):
105105
('D', 'C'),
106106
('D', 'C'),
107107
('D', 'C')])
108+
109+
110+
class TestWorseAndWorse2(TestPlayer):
111+
112+
name = "Worse and Worse 2"
113+
player = axelrod.WorseAndWorse2
114+
expected_classifier = {
115+
'memory_depth': float('inf'),
116+
'stochastic': True,
117+
'makes_use_of': set(),
118+
'long_run_time': False,
119+
'inspects_source': False,
120+
'manipulates_source': False,
121+
'manipulates_state': False
122+
}
123+
124+
def test_strategy(self):
125+
"""
126+
Test that the strategy gives expected behaviour
127+
"""
128+
129+
# Test that first move is C
130+
self.first_play_test('C')
131+
132+
# Test that given a history, next move matches opponent (round <= 20)
133+
self.responses_test([C], [C], [C])
134+
self.responses_test([C, C], [C, D], [D])
135+
self.responses_test([C] * 19, [C] * 19, [C])
136+
self.responses_test([C] * 19, [C] * 18 + [D], [D])
137+
138+
# Test that after round 20, strategy follows stochastic behaviour given
139+
# a seed
140+
self.responses_test([C] * 20, [C] * 20, [C, D, C, C, C, C, D, C, C, C], random_seed=8)
141+
self.responses_test([C] * 20, [C] * 20, [D, D, C, C, D, C, C, C, C, C], random_seed=2)
142+
143+
144+
class TestWorseAndWorse3(TestPlayer):
145+
146+
name = "Worse and Worse 3"
147+
player = axelrod.WorseAndWorse3
148+
expected_classifier = {
149+
'memory_depth': float('inf'),
150+
'stochastic': True,
151+
'makes_use_of': set(),
152+
'long_run_time': False,
153+
'inspects_source': False,
154+
'manipulates_source': False,
155+
'manipulates_state': False
156+
}
157+
158+
def test_strategy(self):
159+
"""
160+
Test that the strategy gives expected behaviour
161+
"""
162+
163+
# Test that first move is C
164+
self.first_play_test('C')
165+
166+
# Test that if opponent only defects, strategy also defects
167+
self.responses_test([D] * 5, [D] * 5, [D])
168+
169+
# Test that if opponent only cooperates, strategy also cooperates
170+
self.responses_test([C] * 5, [C] * 5, [C])
171+
172+
# Test that given a non 0/1 probability of defecting, strategy follows
173+
# stochastic behaviour, given a seed
174+
self.responses_test([C] * 5, [C, D, C, D, C], [D, C, C, D, C, C, C, C, C, C], random_seed=8)
175+
self.responses_test([C] * 5, [D] * 5, [D, D, D, C, C, D, D, D, C, C], random_seed=2)

docs/reference/all_strategies.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ Here are the docstrings of all the strategies in the library.
3333
.. automodule:: axelrod.strategies.backstabber
3434
:members:
3535
:undoc-members:
36+
.. automodule:: axelrod.strategies.better_and_better
37+
:members:
38+
:undoc-members:
3639
.. automodule:: axelrod.strategies.calculator
3740
:members:
3841
:undoc-members:

docs/tutorials/advanced/classification_of_strategies.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ strategies::
4747
... }
4848
>>> strategies = axl.filtered_strategies(filterset)
4949
>>> len(strategies)
50-
55
50+
58
5151

5252

5353
Or, to find out how many strategies only use 1 turn worth of memory to

0 commit comments

Comments
 (0)