Skip to content

Commit f4e162b

Browse files
committed
Address comments from @marcharper (RevisedDowning)
1 parent d8cee8d commit f4e162b

File tree

4 files changed

+125
-4
lines changed

4 files changed

+125
-4
lines changed

axelrod/strategies/_strategies.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
SecondByCave,
2727
SecondByChampion,
2828
SecondByColbert,
29+
SecondByDowning,
2930
SecondByEatherley,
3031
SecondByGetzler,
3132
SecondByGladstein,
@@ -366,6 +367,7 @@
366367
MindReader,
367368
MindWarper,
368369
MirrorMindReader,
370+
SecondByDowning,
369371
SecondByGrofman,
370372
SecondByTidemanAndChieruzzi,
371373
Negation,

axelrod/strategies/axelrod_first.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,23 @@ class FirstByDowning(Player):
189189
is assumed to be the behaviour. Interestingly, in future tournaments this
190190
strategy was revised to not defect on the opening two rounds.
191191
192-
Note that response to the first round allows us to estimate
192+
It is assumed that these first two rounds are used to create initial
193+
estimates of
193194
beta = P(C_o | D_s) and we will use the opening play of the player to
194-
estimate alpha = P(C_o | C_s). This is an assumption with no clear
195-
indication from the literature.
195+
estimate alpha = P(C_o | C_s).
196+
Thus we assume that the opponents first play is a response to a cooperation
197+
"before the match starts".
198+
199+
So for example, if the plays are:
200+
201+
[(D, C), (D, C)]
202+
203+
Then the opponent's first cooperation counts as a cooperation in response to
204+
the non existent cooperation of round 0. The total number of cooperations in
205+
response to a cooperation is 1. We need to take in to account that extra
206+
phantom cooperation to estimate the probability alpha=P(C|C) as 1 / 1 = 1.
207+
208+
This is an assumption with no clear indication from the literature.
196209
197210
--
198211
This strategy came 10th in Axelrod's original tournament.
@@ -236,7 +249,10 @@ def strategy(self, opponent: Player) -> Action:
236249
self.number_opponent_cooperations_in_response_to_D += 1
237250

238251
alpha = (self.number_opponent_cooperations_in_response_to_C /
239-
(self.cooperations + 1)) # Adding 1 to count for opening move
252+
(self.cooperations + 1)) # Adding 1 to count for assumption
253+
# that first opponent move being a
254+
# response to a cooperation. See
255+
# docstring for more information.
240256
beta = (self.number_opponent_cooperations_in_response_to_D /
241257
(self.defections))
242258

axelrod/strategies/axelrod_second.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,71 @@ def strategy(self, opponent: Player) -> Action:
6161
return D
6262
return C
6363

64+
class SecondByDowning(Player):
65+
"""
66+
Strategy submitted to Axelrod's second tournament by Leslie Downing.
67+
(K59R).
68+
69+
Revised Downing attempts to determine if players are cooperative or not.
70+
If so, it cooperates with them.
71+
72+
This strategy is a revision of the strategy submitted by Downing to
73+
Axelrod's first tournament.
74+
75+
76+
Names:
77+
- Revised Downing: [Axelrod1980]_
78+
"""
79+
80+
name = "Second by Downing"
81+
82+
classifier = {
83+
"memory_depth": float("inf"),
84+
"stochastic": False,
85+
"makes_use_of": set(),
86+
"long_run_time": False,
87+
"inspects_source": False,
88+
"manipulates_source": False,
89+
"manipulates_state": False,
90+
}
91+
92+
def __init__(self) -> None:
93+
super().__init__()
94+
self.good = 1.0
95+
self.bad = 0.0
96+
self.nice1 = 0
97+
self.nice2 = 0
98+
self.total_C = 0 # note the same as self.cooperations
99+
self.total_D = 0 # note the same as self.defections
100+
101+
def strategy(self, opponent: Player) -> Action:
102+
round_number = len(self.history) + 1
103+
104+
if round_number == 1:
105+
return C
106+
107+
# Update various counts
108+
if round_number > 2:
109+
if self.history[-1] == D:
110+
if opponent.history[-1] == C:
111+
self.nice2 += 1
112+
self.total_D += 1
113+
self.bad = self.nice2 / self.total_D
114+
else:
115+
if opponent.history[-1] == C:
116+
self.nice1 += 1
117+
self.total_C += 1
118+
self.good = self.nice1 / self.total_C
119+
# Make a decision based on the accrued counts
120+
c = 6.0 * self.good - 8.0 * self.bad - 2
121+
alt = 4.0 * self.good - 5.0 * self.bad - 1
122+
if c >= 0 and c >= alt:
123+
move = C
124+
elif (c >= 0 and c < alt) or (alt >= 0):
125+
move = self.history[-1].flip()
126+
else:
127+
move = D
128+
return move
64129

65130
class SecondByEatherley(Player):
66131
"""

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,3 +2030,41 @@ def test_strategy(self):
20302030
(C, C),
20312031
(D, C)]
20322032
self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=7)
2033+
2034+
2035+
class TestSeconodByDowning(TestPlayer):
2036+
2037+
name = "Revised Downing"
2038+
player = axelrod.SecondByDowning
2039+
expected_classifier = {
2040+
"memory_depth": float("inf"),
2041+
"stochastic": False,
2042+
"makes_use_of": set(),
2043+
"long_run_time": False,
2044+
"inspects_source": False,
2045+
"manipulates_source": False,
2046+
"manipulates_state": False,
2047+
}
2048+
2049+
def test_strategy(self):
2050+
actions = [(C, C), (C, C), (C, C)]
2051+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
2052+
2053+
actions = [(C, D), (C, D), (D, D)]
2054+
self.versus_test(axelrod.Defector(), expected_actions=actions)
2055+
2056+
opponent = axelrod.MockPlayer(actions=[D, C, C])
2057+
actions = [(C, D), (C, C), (C, C), (C, D)]
2058+
self.versus_test(opponent, expected_actions=actions)
2059+
2060+
opponent = axelrod.MockPlayer(actions=[D, D, C])
2061+
actions = [(C, D), (C, D), (D, C), (D, D)]
2062+
self.versus_test(opponent, expected_actions=actions)
2063+
2064+
opponent = axelrod.MockPlayer(actions=[C, C, D, D, C, C])
2065+
actions = [(C, C), (C, C), (C, D), (C, D), (D, C), (D, C), (D, C)]
2066+
self.versus_test(opponent, expected_actions=actions)
2067+
2068+
opponent = axelrod.MockPlayer(actions=[C, C, C, C, D, D])
2069+
actions = [(C, C), (C, C), (C, C), (C, C), (C, D), (C, D), (C, C)]
2070+
self.versus_test(opponent, expected_actions=actions)

0 commit comments

Comments
 (0)