Skip to content

Commit 66de2da

Browse files
gaffney2010drvinceknight
authored andcommitted
Added Appold (k88r) strategy from Axelrod's second. (#1263)
* Fix bug in Kluepfel strategy * Fix bug in Kluepfel strategy * Add Appold strategy (k88r in Axelrod's second)
1 parent 7daf72a commit 66de2da

File tree

5 files changed

+195
-2
lines changed

5 files changed

+195
-2
lines changed

axelrod/strategies/_strategies.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
UnnamedStrategy,
2121
)
2222
from .axelrod_second import (
23+
Appold,
2324
Black,
2425
Borufsen,
2526
Cave,
@@ -248,6 +249,7 @@
248249
APavlov2006,
249250
APavlov2011,
250251
Appeaser,
252+
Appold,
251253
ArrogantQLearner,
252254
AverageCopier,
253255
BackStabber,

axelrod/strategies/axelrod_second.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,3 +2059,72 @@ def strategy(self, opponent: Player) -> Action:
20592059
self.mode = "Coop Def Cycle 1"
20602060
return D
20612061

2062+
2063+
class Appold(Player):
2064+
"""
2065+
Strategy submitted to Axelrod's second tournament by Scott Appold (K88R) and
2066+
came in 22nd in that tournament.
2067+
2068+
Cooperates for first four turns.
2069+
2070+
After four turns, will cooperate immediately following the first time the
2071+
opponent cooperates (starting with the opponent's fourth move). Otherwise
2072+
will cooperate with probability equal to:
2073+
2074+
- If this strategy defected two turns ago, the portion of the time
2075+
(historically) that the opponent followed a defection with a cooperation.
2076+
- If this strategy cooperated two turns ago, the portion of the time
2077+
(historically) that the opponent followed a cooperation with a cooperation.
2078+
The opponent's first move is counted as a response to a cooperation.
2079+
2080+
2081+
Names:
2082+
2083+
- Appold: [Axelrod1980b]_
2084+
"""
2085+
2086+
name = "Appold"
2087+
classifier = {
2088+
"memory_depth": float("inf"),
2089+
"stochastic": True,
2090+
"makes_use_of": set(),
2091+
"long_run_time": False,
2092+
"inspects_source": False,
2093+
"manipulates_source": False,
2094+
"manipulates_state": False,
2095+
}
2096+
2097+
def __init__(self) -> None:
2098+
super().__init__()
2099+
2100+
# Probability of a cooperation after an x is:
2101+
# opp_c_after_x / total_num_of_x.
2102+
self.opp_c_after_x = {C: 0, D: 1}
2103+
# This is the total counted, so it doesn't include the most recent.
2104+
self.total_num_of_x = {C: 0, D: 1}
2105+
2106+
self.first_opp_def = False
2107+
2108+
def strategy(self, opponent: Player) -> Action:
2109+
turn = len(self.history) + 1
2110+
2111+
us_two_turns_ago = C if turn <= 2 else self.history[-2]
2112+
2113+
# Update trackers
2114+
if turn > 1:
2115+
self.total_num_of_x[us_two_turns_ago] += 1
2116+
if turn > 1 and opponent.history[-1] == C:
2117+
self.opp_c_after_x[us_two_turns_ago] += 1
2118+
2119+
if turn <= 4:
2120+
return C
2121+
2122+
if opponent.history[-1] == D and not self.first_opp_def:
2123+
self.first_opp_def = True
2124+
return C
2125+
2126+
# Calculate the probability that the opponent cooperated last turn given
2127+
# what we know two turns ago.
2128+
prob_coop = self.opp_c_after_x[us_two_turns_ago] / self.total_num_of_x[
2129+
us_two_turns_ago]
2130+
return random_choice(prob_coop)

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,3 +1908,125 @@ def test_strategy(self):
19081908
self.versus_test(custom_opponent, expected_actions=actions, attrs={
19091909
"distrust_points": 2}) # But no more
19101910

1911+
1912+
class TestAppold(TestPlayer):
1913+
name = "Appold"
1914+
player = axelrod.Appold
1915+
expected_classifier = {
1916+
"memory_depth": float("inf"),
1917+
"stochastic": True,
1918+
"makes_use_of": set(),
1919+
"long_run_time": False,
1920+
"inspects_source": False,
1921+
"manipulates_source": False,
1922+
"manipulates_state": False,
1923+
}
1924+
1925+
def test_strategy(self):
1926+
# Should cooperate 100% of the time with the cooperator
1927+
actions = [(C, C)] * 100
1928+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
1929+
1930+
opponent = axelrod.Defector()
1931+
# Cooperate always the first 4 turns
1932+
actions = [(C, D)] * 4
1933+
# Should cooperate because we forgive the first_opp_def after the fourth
1934+
# turn.
1935+
actions += [(C, D)]
1936+
# Own move two turns ago is C, so D.
1937+
actions += [(D, D)]
1938+
# Then defect most of the time, depending on the random number. We
1939+
# don't defect 100% of the time, because of the way that initialize
1940+
# opp_c_after_x.
1941+
actions += [(D, D),
1942+
(C, D),
1943+
(D, D),
1944+
(D, D), # C can never be two moves after a C.
1945+
(D, D),
1946+
(D, D),
1947+
(D, D),
1948+
(D, D),
1949+
(D, D),
1950+
(D, D),
1951+
(C, D),
1952+
(C, D),
1953+
(D, D),
1954+
(D, D),
1955+
(D, D),
1956+
(D, D),
1957+
(D, D),
1958+
(C, D),
1959+
(D, D),
1960+
(D, D),
1961+
(D, D),
1962+
(D, D),
1963+
(D, D),
1964+
(D, D),
1965+
(C, D),
1966+
(C, D),
1967+
(D, D),
1968+
(D, D)]
1969+
self.versus_test(opponent, expected_actions=actions, seed=1,
1970+
attrs={"first_opp_def": True})
1971+
1972+
# An opponent who defects for a long time, then tries cooperating
1973+
opponent_actions = [C] * 30 + [D] + [C] * 10
1974+
MostlyCooperates = axelrod.MockPlayer(actions=opponent_actions)
1975+
# Cooperate always at first
1976+
actions = [(C, C)] * 30
1977+
# The opponent defects once
1978+
actions += [(C, D)]
1979+
# But we forgive it.
1980+
actions += [(C, C)] * 10
1981+
self.versus_test(MostlyCooperates, expected_actions=actions)
1982+
1983+
opponent = axelrod.CyclerDC()
1984+
# First three opponent actions get counted as reactions to C. Fourth
1985+
# action will get counted on next turn.
1986+
actions = [(C, D), (C, C), (C, D), (C, C)]
1987+
self.versus_test(opponent, expected_actions=actions,
1988+
attrs={"opp_c_after_x": {C: 1, D: 1},
1989+
"total_num_of_x": {C: 3, D: 1}})
1990+
# Will cooperate 50% of the time
1991+
actions += [(C, D)]
1992+
self.versus_test(opponent, expected_actions=actions,
1993+
attrs={"opp_c_after_x": {C: 2, D: 1},
1994+
"total_num_of_x": {C: 4, D: 1},
1995+
"first_opp_def": False}, seed=100)
1996+
# Always cooperate, because we forgive the first defect
1997+
actions += [(C, C)]
1998+
self.versus_test(opponent, expected_actions=actions,
1999+
attrs={"first_opp_def": True}, seed=100)
2000+
2001+
# Against a random opponent, will respond mostly randomly too.
2002+
actions = [(C, C),
2003+
(C, C),
2004+
(C, D),
2005+
(C, C),
2006+
(C, C),
2007+
(C, D),
2008+
(C, C),
2009+
(C, C),
2010+
(C, C),
2011+
(D, C),
2012+
(C, D),
2013+
(D, D),
2014+
(C, D),
2015+
(C, D),
2016+
(C, C),
2017+
(C, C),
2018+
(D, C),
2019+
(C, D),
2020+
(D, D),
2021+
(C, C),
2022+
(C, D),
2023+
(C, C),
2024+
(C, C),
2025+
(C, D),
2026+
(D, C),
2027+
(C, D),
2028+
(D, D),
2029+
(C, D),
2030+
(C, C),
2031+
(D, C)]
2032+
self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=7)

docs/reference/overview_of_strategies.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ repository.
115115
"K85R_", "Robert B Falk and James M Langsted", "Not Implemented"
116116
"K86R_", "Bernard Grofman", "Not Implemented"
117117
"K87R_", "E E H Schurmann", "Not Implemented"
118-
"K88R_", "Scott Appold", "Not Implemented"
118+
"K88R_", "Scott Appold", ":class:`Appold <axelrod.strategies.axelrod_second.Appold>`"
119119
"K89R_", "Gene Snodgrass", "Not Implemented"
120120
"K90R_", "John Maynard Smith", "Not Implemented"
121121
"K91R_", "Jonathan Pinkley", "Not Implemented"

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-
86
50+
87
5151

5252
Or, to find out how many strategies only use 1 turn worth of memory to
5353
make a decision::

0 commit comments

Comments
 (0)