Skip to content

Commit a79ccab

Browse files
authored
Merge pull request #1163 from gaffney2010/master
Implemented Yamachi, k64r from Axelrod's Second.
2 parents 4c983c7 + c16f196 commit a79ccab

File tree

4 files changed

+204
-2
lines changed

4 files changed

+204
-2
lines changed

axelrod/strategies/_strategies.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
from .axelrod_second import (
1111
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
1212
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen, Weiner, Harrington,
13-
MoreTidemanAndChieruzzi, Getzler, Leyvraz, White, Black, RichardHufford)
13+
MoreTidemanAndChieruzzi, Getzler, Leyvraz, White, Black, RichardHufford,
14+
Yamachi)
1415
from .backstabber import BackStabber, DoubleCrosser
1516
from .better_and_better import BetterAndBetter
1617
from .bush_mosteller import BushMosteller
@@ -288,6 +289,7 @@
288289
WorseAndWorse,
289290
WorseAndWorse2,
290291
WorseAndWorse3,
292+
Yamachi,
291293
ZDExtortion,
292294
ZDExtort2,
293295
ZDExtort3,

axelrod/strategies/axelrod_second.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import random
66
import numpy as np
7+
from typing import List
78

89
from axelrod.action import Action
910
from axelrod.player import Player
@@ -1709,3 +1710,96 @@ def strategy(self, opponent: Player) -> Action:
17091710
elif proportion_agree >= 0.625 and last_four_num >= 2:
17101711
return opponent.history[-1]
17111712
return D
1713+
1714+
1715+
class Yamachi(Player):
1716+
"""
1717+
Strategy submitted to Axelrod's second tournament by Brian Yamachi (K64R)
1718+
and came in seventeenth in that tournament.
1719+
1720+
The strategy keeps track of play history through a variable called
1721+
`count_them_us_them`, which is a dict indexed by (X, Y, Z), where X is an
1722+
opponent's move and Y and Z are the following moves by this player and the
1723+
opponent, respectively. Each turn, we look at our opponent's move two
1724+
turns ago, call X, and our move last turn, call Y. If (X, Y, C) has
1725+
occurred more often (or as often) as (X, Y, D), then Cooperate. Otherwise
1726+
Defect. [Note that this reflects likelihood of Cooperations or Defections
1727+
in opponent's previous move; we don't update `count_them_us_them` with
1728+
previous move until next turn.]
1729+
1730+
Starting with the 41st turn, there's a possibility to override this
1731+
behavior. If `portion_defect` is between 45% and 55% (exclusive), then
1732+
Defect, where `portion_defect` equals number of opponent defects plus 0.5
1733+
divided by the turn number (indexed by 1). When overriding this way, still
1734+
record `count_them_us_them` as though the strategy didn't override.
1735+
1736+
Names:
1737+
1738+
- Yamachi: [Axelrod1980b]_
1739+
"""
1740+
1741+
name = 'Yamachi'
1742+
classifier = {
1743+
'memory_depth': float("inf"),
1744+
'stochastic': False,
1745+
'makes_use_of': set(),
1746+
'long_run_time': False,
1747+
'inspects_source': False,
1748+
'manipulates_source': False,
1749+
'manipulates_state': False
1750+
}
1751+
1752+
def __init__(self) -> None:
1753+
super().__init__()
1754+
self.count_them_us_them = {(C, C, C): 0,
1755+
(C, C, D): 0,
1756+
(C, D, C): 0,
1757+
(C, D, D): 0,
1758+
(D, C, C): 0,
1759+
(D, C, D): 0,
1760+
(D, D, C): 0,
1761+
(D, D, D): 0}
1762+
self.mod_history = list() # type: List[Action]
1763+
1764+
def try_return(self, to_return, opp_def):
1765+
"""
1766+
Return `to_return`, unless the turn is greater than 40 AND
1767+
`portion_defect` is between 45% and 55%.
1768+
1769+
In this case, still record the history as `to_return` so that the
1770+
modified behavior doesn't affect the calculation of `count_us_them_us`.
1771+
"""
1772+
turn = len(self.history) + 1
1773+
1774+
self.mod_history.append(to_return)
1775+
1776+
# In later turns, check if the opponent is close to 50/50
1777+
# If so, then override
1778+
if turn > 40:
1779+
portion_defect = (opp_def + 0.5) / turn
1780+
if 0.45 < portion_defect and portion_defect < 0.55:
1781+
return D
1782+
1783+
return to_return
1784+
1785+
def strategy(self, opponent: Player) -> Action:
1786+
turn = len(self.history) + 1
1787+
if turn == 1:
1788+
return self.try_return(C, 0)
1789+
1790+
us_last = self.mod_history[-1]
1791+
them_two_ago, us_two_ago, them_three_ago = C, C, C
1792+
if turn >= 3:
1793+
them_two_ago = opponent.history[-2]
1794+
us_two_ago = self.mod_history[-2]
1795+
if turn >= 4:
1796+
them_three_ago = opponent.history[-3]
1797+
1798+
# Update history
1799+
if turn >= 3:
1800+
self.count_them_us_them[(them_three_ago, us_two_ago, them_two_ago)] += 1
1801+
1802+
if self.count_them_us_them[(them_two_ago, us_last, C)] >= \
1803+
self.count_them_us_them[(them_two_ago, us_last, D)]:
1804+
return self.try_return(C, opponent.defections)
1805+
return self.try_return(D, opponent.defections)

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,3 +1055,109 @@ def test_strategy(self):
10551055
actions += [(D, D)] # Three of last four are disagreements.
10561056
actions += [(D, D)] # Now there are 5/9 disagreements, so Defect.
10571057
self.versus_test(axelrod.WinShiftLoseStay(), expected_actions=actions, attrs={"num_agreements": 5})
1058+
1059+
1060+
class TestYamachi(TestPlayer):
1061+
name = 'Yamachi'
1062+
player = axelrod.Yamachi
1063+
expected_classifier = {
1064+
'memory_depth': float('inf'),
1065+
'stochastic': False,
1066+
'makes_use_of': set(),
1067+
'long_run_time': False,
1068+
'inspects_source': False,
1069+
'manipulates_source': False,
1070+
'manipulates_state': False
1071+
}
1072+
1073+
def test_strategy(self):
1074+
actions = [(C, C)] * 100
1075+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
1076+
1077+
actions = [(C, D)] * 2 # Also Cooperate in first two moves (until we update `count_them_us_them`.)
1078+
actions += [(C, D)] # them_three_ago defaults to C, so that (C, C, *) gets updated, then (D, C, *) get checked.
1079+
# It's actually impossible to Defect on the third move.
1080+
actions += [(D, D)] # (D, C, *) gets updated, then checked.
1081+
actions += [(C, D)] # (D, C, *) gets updated, but (D, D, *) checked.
1082+
actions += [(D, D)] * 30 # (D, D, *) gets updated and checked from here on.
1083+
self.versus_test(axelrod.Defector(), expected_actions=actions)
1084+
1085+
actions = [(C, C), (C, D)]
1086+
actions += [(C, C)] # Increment (C, C, C). Check (C, C, *). Cooperate.
1087+
# Reminder that first C is default value and last C is opponent's first move.
1088+
actions += [(C, D)] # Increment (C, C, D). Check (D, C, *) = 0. Cooperate.
1089+
actions += [(C, C)] # Increment (D, C, C). Check (C, C, *) = 0. Cooperate.
1090+
# There is one Defection and one Cooperation in this scenario,
1091+
# but the Cooperation was due to a default value only. We can see where this is going.
1092+
actions += [(C, D)] # Increment (C, C, D). Check (D, C, *) = 1. Cooperate.
1093+
actions += [(D, C)] # Increment (D, C, C). Check (C, C, *) = -1. Defect.
1094+
actions += [(C, D)] # Increment (C, C, D). Check (D, D, *) = 0 (New). Cooperate.
1095+
actions += [(D, C)] # Increment (D, D, C). Check (C, C, *) < 0. Defect.
1096+
actions += [(C, D)] # Increment (C, C, D). Check (D, D, *) > 0. Cooperate.
1097+
actions += [(D, C), (C, D)] * 15 # This pattern continues for a while.
1098+
actions += [(D, C), (D, D)] * 30 # Defect from turn 41 on, since near 50% Defections.
1099+
self.versus_test(axelrod.Alternator(), expected_actions=actions)
1100+
1101+
# Rip-off is the most interesting interaction.
1102+
actions = [(C, D),
1103+
(C, C),
1104+
(C, D),
1105+
(D, C),
1106+
(C, C),
1107+
(D, C),
1108+
(C, D),
1109+
(D, C),
1110+
(C, D),
1111+
(D, C),
1112+
(C, D),
1113+
(D, C),
1114+
(C, D),
1115+
(D, C),
1116+
(C, D),
1117+
(D, C),
1118+
(C, D),
1119+
(D, C),
1120+
(C, D),
1121+
(D, C),
1122+
(C, D),
1123+
(D, C),
1124+
(C, D),
1125+
(D, C),
1126+
(C, D),
1127+
(D, C),
1128+
(C, D),
1129+
(D, C),
1130+
(C, D),
1131+
(D, C),
1132+
(C, D),
1133+
(D, C),
1134+
(C, D),
1135+
(D, C),
1136+
(C, D),
1137+
(D, C),
1138+
(C, D),
1139+
(D, C),
1140+
(C, D),
1141+
(D, C)]
1142+
my_dict = {(C, C, C): 1,
1143+
(C, C, D): 18,
1144+
(C, D, C): 1,
1145+
(C, D, D): 0,
1146+
(D, C, C): 1,
1147+
(D, C, D): 0,
1148+
(D, D, C): 17,
1149+
(D, D, D): 0}
1150+
RipoffPlayer = axelrod.Ripoff()
1151+
self.versus_test(RipoffPlayer, expected_actions=actions, attrs={"count_them_us_them": my_dict})
1152+
self.assertEqual(RipoffPlayer.defections, 19) # Next turn, `portion_defect` = 0.4756
1153+
1154+
# The pattern (C, D), (D, C) will continue indefintely unless overriden.
1155+
actions += [(D, D)] # Next turn, `portion_defect` = 0.4881
1156+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5
1157+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5114
1158+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5222
1159+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5326
1160+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5426
1161+
actions += [(D, D)] # Next turn, `portion_defect` = 0.5521
1162+
actions += [(D, D), (C, D), (D, C), (C, D)] # Takes a turn to fall back into the cycle.
1163+
self.versus_test(axelrod.Ripoff(), expected_actions=actions)

docs/reference/overview_of_strategies.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ repository.
132132
"K61R_", "Danny C Champion", ":class:`Champion <axelrod.strategies.axelrod_second.Champion>`"
133133
"K62R_", "Howard R Hollander", "Not Implemented"
134134
"K63R_", "George Duisman", "Not Implemented"
135-
"K64R_", "Brian Yamachi", "Not Implemented"
135+
"K64R_", "Brian Yamachi", ":class:`Yamachi <axelrod.strategies.axelrod_second.Yamachi>`"
136136
"K65R_", "Mark F Batell", "Not Implemented"
137137
"K66R_", "Ray Mikkelson", "Not Implemented"
138138
"K67R_", "Craig Feathers", ":class:`Tranquilizer <axelrod.strategies.axelrod_second.Tranquilizer>`"

0 commit comments

Comments
 (0)