Skip to content

Commit 0a281c5

Browse files
Merge pull request #1228 from gaffney2010/master
Added Rowsam (k58r) strategy from Axelrod's second.
2 parents 07daefc + baa47eb commit 0a281c5

File tree

4 files changed

+202
-1
lines changed

4 files changed

+202
-1
lines changed

axelrod/strategies/_strategies.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
MoreGrofman,
3636
MoreTidemanAndChieruzzi,
3737
RichardHufford,
38+
Rowsam,
3839
Tester,
3940
Tranquilizer,
4041
Weiner,
@@ -388,6 +389,7 @@
388389
RichardHufford,
389390
Ripoff,
390391
RiskyQLearner,
392+
Rowsam,
391393
SelfSteem,
392394
ShortMem,
393395
Shubik,

axelrod/strategies/axelrod_second.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,3 +1953,109 @@ def strategy(self, opponent: Player) -> Action:
19531953
if opponent.defections / turn >= 0.15:
19541954
return D
19551955
return C
1956+
1957+
1958+
class Rowsam(Player):
1959+
"""
1960+
Strategy submitted to Axelrod's second tournament by Glen Rowsam (K58R)
1961+
and came in 21st in that tournament.
1962+
1963+
The strategy starts in Normal mode, where it cooperates every turn. Every
1964+
six turns it checks the score per turn. [Rather the score of all previous
1965+
turns divided by the turn number, which will be one more than the number of
1966+
turns scored.] If this measure is less than 2.5 (the strategy is doing
1967+
badly) and it increases `distrust_points`. `distrust_points` is a variable
1968+
that starts at 0; if it ever exceeds 6 points, the strategy will enter
1969+
Defect mode and defect from then on. It will increase `distrust_points`
1970+
depending on the precise score per turn according to:
1971+
1972+
- 5 points if score per turn is less than 1.0
1973+
- 3 points if score per turn is less than 1.5, but at least 1.0
1974+
- 2 points if score per turn is less than 2.0, but at least 1.5
1975+
- 1 points if score per turn is less than 2.5, but at least 2.0
1976+
1977+
If `distrust_points` are increased, then the strategy defects on that turn,
1978+
then cooperates and defects on the next two turns. [Unless
1979+
`distrust_points` exceeds 6 points, then it will enter Defect mode
1980+
immediately.]
1981+
1982+
Every 18 turns in Normal mode, the strategy will decrement `distrust_score`
1983+
if it's more than 3. This represents a wearing off effect of distrust.
1984+
1985+
1986+
Names:
1987+
1988+
- Rowsam: [Axelrod1980b]_
1989+
"""
1990+
1991+
name = "Rowsam"
1992+
classifier = {
1993+
"memory_depth": float("inf"),
1994+
"stochastic": False,
1995+
"makes_use_of": set("game"),
1996+
"long_run_time": False,
1997+
"inspects_source": False,
1998+
"manipulates_source": False,
1999+
"manipulates_state": False,
2000+
}
2001+
2002+
def __init__(self) -> None:
2003+
super().__init__()
2004+
self.mode = "Normal"
2005+
self.distrust_points = 0
2006+
self.current_score = 0
2007+
self.opponent_score = 0
2008+
2009+
def _score_last_round(self, opponent: Player):
2010+
"""Updates the scores for each player."""
2011+
game = self.match_attributes["game"]
2012+
last_round = (self.history[-1], opponent.history[-1])
2013+
scores = game.score(last_round)
2014+
self.current_score += scores[0]
2015+
self.opponent_score += scores[1]
2016+
2017+
def strategy(self, opponent: Player) -> Action:
2018+
turn = len(self.history) + 1
2019+
if turn > 1:
2020+
self._score_last_round(opponent)
2021+
2022+
if self.mode == "Defect":
2023+
return D
2024+
2025+
if self.mode == "Coop Def Cycle 1":
2026+
self.mode = "Coop Def Cycle 2"
2027+
return C
2028+
2029+
if self.mode == "Coop Def Cycle 2":
2030+
self.mode = "Normal"
2031+
return D
2032+
2033+
# Opportunity for distrust to cool off.
2034+
if turn % 18 == 0:
2035+
if self.distrust_points >= 3:
2036+
self.distrust_points -= 1
2037+
2038+
# In normal mode, only check for strategy updates every sixth turn.
2039+
if turn % 6 != 0:
2040+
return C
2041+
2042+
points_per_turn = self.current_score / turn # Off by one
2043+
if points_per_turn < 1.0:
2044+
self.distrust_points += 5
2045+
elif points_per_turn < 1.5:
2046+
self.distrust_points += 3
2047+
elif points_per_turn < 2.0:
2048+
self.distrust_points += 2
2049+
elif points_per_turn < 2.5:
2050+
self.distrust_points += 1
2051+
else:
2052+
# Continue Cooperating
2053+
return C
2054+
2055+
if self.distrust_points >= 7:
2056+
self.mode = "Defect"
2057+
else:
2058+
# Def this time, then coop, then def.
2059+
self.mode = "Coop Def Cycle 1"
2060+
return D
2061+

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,3 +1815,96 @@ def test_strategy(self):
18151815
Change_of_Heart, expected_actions=actions, attrs={"credit": -2}
18161816
)
18171817
# Still Cooperate, because Defect rate is low
1818+
1819+
class TestRowsam(TestPlayer):
1820+
name = "Rowsam"
1821+
player = axelrod.Rowsam
1822+
expected_classifier = {
1823+
"memory_depth": float("inf"),
1824+
"stochastic": False,
1825+
"makes_use_of": set("game"),
1826+
"long_run_time": False,
1827+
"inspects_source": False,
1828+
"manipulates_source": False,
1829+
"manipulates_state": False,
1830+
}
1831+
1832+
def test_strategy(self):
1833+
# Should always cooperate with Cooperator
1834+
actions = [(C, C)] * 100
1835+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
1836+
1837+
# Against a Defector should eventually enter Defect mode
1838+
actions = [(C, D)] * 5
1839+
actions += [(D, D), (C, D), (D, D)] # Do a Coop-Def cycle
1840+
self.versus_test(axelrod.Defector(), expected_actions=actions, attrs={
1841+
"distrust_points": 5})
1842+
actions += [(C, D)] * 3 # Continue for now
1843+
actions += [(D, D)] * 100 # Now Defect mode
1844+
self.versus_test(axelrod.Defector(), expected_actions=actions, attrs={
1845+
"distrust_points": 10, "mode": "Defect"})
1846+
1847+
# Test specific score scenarios
1848+
# 5 Defects
1849+
opponent_actions = [D] * 5 + [C] * 100
1850+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1851+
actions = [(C, D)] * 5
1852+
actions += [(D, C)]
1853+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1854+
"distrust_points": 5, "current_score": 0})
1855+
1856+
# 3 Defects
1857+
opponent_actions = [D] * 3 + [C] * 100
1858+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1859+
actions = [(C, D)] * 3
1860+
actions += [(C, C)] * 2
1861+
actions += [(D, C)]
1862+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1863+
"distrust_points": 3, "current_score": 6})
1864+
1865+
# 2 Defects
1866+
opponent_actions = [D] * 2 + [C] * 100
1867+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1868+
actions = [(C, D)] * 2
1869+
actions += [(C, C)] * 3
1870+
actions += [(D, C)]
1871+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1872+
"distrust_points": 2, "current_score": 9})
1873+
1874+
# 1 Defect
1875+
opponent_actions = [D] * 1 + [C] * 100
1876+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1877+
actions = [(C, D)] * 1
1878+
actions += [(C, C)] * 4
1879+
actions += [(D, C)]
1880+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1881+
"distrust_points": 1, "current_score": 12})
1882+
1883+
# Test that some distrust_points wear off.
1884+
opponent_actions = [D] * 3 + [C] * 100
1885+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1886+
actions = [(C, D)] * 3
1887+
actions += [(C, C)] * 2
1888+
actions += [(D, C)]
1889+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1890+
"distrust_points": 3, "current_score": 6})
1891+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1892+
actions += [(C, C), (D, C)] # Complete Coop-Def cycle
1893+
actions += [(C, C)] * 3
1894+
actions += [(D, C)]
1895+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1896+
"distrust_points": 4, "current_score": 28})
1897+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1898+
actions += [(C, C), (D, C)] # Complete Coop-Def cycle
1899+
actions += [(C, C)] * 4 # No defect or cycle this time.
1900+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1901+
"distrust_points": 3, "current_score": 50}) # One point wears off.
1902+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1903+
actions += [(C, C)] * 18
1904+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1905+
"distrust_points": 2}) # Second point wears off
1906+
custom_opponent = axelrod.MockPlayer(actions=opponent_actions)
1907+
actions += [(C, C)] * 18
1908+
self.versus_test(custom_opponent, expected_actions=actions, attrs={
1909+
"distrust_points": 2}) # But no more
1910+

docs/reference/overview_of_strategies.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ repository.
126126
"K55R_", "Steve Newman", "Not Implemented"
127127
"K56R_", "Stanley F Quayle", "Not Implemented"
128128
"K57R_", "Rudy Nydegger", "Not Implemented"
129-
"K58R_", "Glen Rowsam", "Not Implemented"
129+
"K58R_", "Glen Rowsam", ":class:`Rowsam <axelrod.strategies.axelrod_second.Rowsam>`"
130130
"K59R_", "Leslie Downing", "Not Implemented"
131131
"K60R_", "Jim Graaskamp and Ken Katzen", ":class:`GraaskampKatzen <axelrod.strategies.axelrod_second.GraaskampKatzen>`"
132132
"K61R_", "Danny C Champion", ":class:`Champion <axelrod.strategies.axelrod_second.Champion>`"

0 commit comments

Comments
 (0)