Skip to content

Commit 9c9f3a7

Browse files
committed
Rework AdaptiveZeroDet to be a subclass of LRPlayer
1 parent 318e37e commit 9c9f3a7

File tree

2 files changed

+204
-120
lines changed

2 files changed

+204
-120
lines changed

axelrod/strategies/adaptivezerodet.py

Lines changed: 125 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,125 @@
1-
from axelrod.action import Action
2-
from axelrod.player import Player
3-
from axelrod.random_ import random_choice
4-
from typing import Tuple
5-
from typing import List
6-
7-
C, D = Action.C, Action.D
8-
9-
class AdaptiveZeroDet(Player):
10-
name = 'AdaptiveZeroDet'
11-
classifier = {
12-
'memory_depth': float('inf'), # Long memory
13-
'stochastic': True,
14-
'makes_use_of': set(["game"]),
15-
'long_run_time': False,
16-
'inspects_source': False,
17-
'manipulates_source': False,
18-
'manipulates_state': False
19-
}
20-
def __init__(self, phi: float = 0.125, s: float = 0.5, l: float = 3, four_vector: Tuple[float, float, float, float] = None, initial: Action = C) -> None:
21-
# This Keeps track of the parameter values (phi,s,l) as well as the four vector which makes final decisions.
22-
self.scores = {C: 0, D: 0}
23-
self.phi = phi
24-
self.s = s
25-
self.l = l
26-
self._initial = initial
27-
super().__init__()
28-
29-
def set_four_vector(self, four_vector: Tuple[float, float, float, float]):
30-
# This checks the four vector is usable and allows previous matches' output to be input for next four vector
31-
if not all(0 <= p <= 1 for p in four_vector):
32-
raise ValueError("An element in the probability vector, {}, is not between 0 and 1.".format(str(four_vector)))
33-
self._four_vector = dict(zip([(C, C), (C, D), (D, C), (D, D)], map(float, four_vector)))
34-
self.classifier['stochastic'] = any(0 < x < 1 for x in set(four_vector))
35-
36-
def score_last_round(self, opponent: Player):
37-
# This gives the strategy the game attributes and allows the strategy to score itself properly
38-
game = self.match_attributes["game"]
39-
if len(self.history):
40-
last_round = (self.history[-1], opponent.history[-1])
41-
scores = game.score(last_round)
42-
self.scores[last_round[0]] += scores[0]
43-
44-
def strategy(self, opponent: Player) -> Action:
45-
s = self.s
46-
phi = self.phi
47-
l = self.l
48-
d = randint(0, 9)/1000 # Selects random value to adjust s and l
49-
if self.scores[C] > self.scores[D] & len(self.history):
50-
# This checks scores to determine how to adjust s and l either up or down by d
51-
# This also checks if the length of the game is long enough to start adjusting
52-
self.l = l+d
53-
l = self.l
54-
# adjust l up
55-
self.s = s-d
56-
s = self.s
57-
# adjust s down
58-
R, P, S, T = self.match_attributes["game"].RPST()
59-
phi = self.phi
60-
s_min = - min((T - l) / (l - S), (l - S) / (T - l)) # Sets minimum for s
61-
if (l > R) or (s < s_min):
62-
# This checks that neither s nor l is leaving its range
63-
if (l > R):
64-
l = l-d
65-
self.l = (l+R)/2
66-
l = self.l
67-
# If l would leave its range instead its distance from its max is halved
68-
if (s < s_min):
69-
s = s+d
70-
self.s = (s+s_min)/2
71-
s = self.s
72-
# If s would leave its range instead its distance from its min is halved
73-
p1 = 1 - phi * (1 - s) * (R - l)
74-
p2 = 1 - phi * (s * (l - S) + (T - l))
75-
p3 = phi * ((l - S) + s * (T - l))
76-
p4 = phi * (1 - s) * (l - P)
77-
four_vector = [p1, p2, p3, p4]
78-
# Four vector is calculated with new parameters
79-
self.set_four_vector(four_vector)
80-
if not hasattr(self, "_four_vector"):
81-
raise ValueError("_four_vector not yet set")
82-
if len(opponent.history) == 0:
83-
return self._initial
84-
p = self._four_vector[(self.history[-1], opponent.history[-1])]
85-
return random_choice(p)
86-
else:
87-
# This adjusts s and l in the opposite direction
88-
self.l = l-d
89-
l = self.l
90-
# adjust l down
91-
self.s = s+d
92-
s = self.s
93-
# adjust s up
94-
R, P, S, T = self.match_attributes["game"].RPST()
95-
phi = self.phi
96-
if (l < P) or (s > 1):
97-
# This checks that neither s nor l is leaving its range
98-
if (l < P):
99-
l = l+d
100-
self.l = (l+P)/2
101-
l = self.l
102-
# If l would leave its range instead its distance from its min is halved
103-
if (s > 1):
104-
s = s-d
105-
self.s = (s+1)/2
106-
s = self.s
107-
# If s would leave its range instead its distance from its max is halved
108-
p1 = 1 - phi * (1 - s) * (R - l)
109-
p2 = 1 - phi * (s * (l - S) + (T - l))
110-
p3 = phi * ((l - S) + s * (T - l))
111-
p4 = phi * (1 - s) * (l - P)
112-
four_vector = [p1, p2, p3, p4]
113-
# Four vector is calculated with new parameters
114-
self.set_four_vector(four_vector)
115-
if not hasattr(self, "_four_vector"):
116-
raise ValueError("_four_vector not yet set")
117-
if len(opponent.history) == 0:
118-
return self._initial
119-
p = self._four_vector[(self.history[-1], opponent.history[-1])]
120-
return random_choice(p)
1+
from typing import Tuple
2+
3+
from axelrod.action import Action
4+
from axelrod.player import Player
5+
from axelrod.random_ import random_choice
6+
7+
C, D = Action.C, Action.D
8+
9+
10+
class AdaptiveZeroDet(Player):
11+
name = 'AdaptiveZeroDet'
12+
classifier = {
13+
'memory_depth': float('inf'), # Long memory
14+
'stochastic': True,
15+
'makes_use_of': set(["game"]),
16+
'long_run_time': False,
17+
'inspects_source': False,
18+
'manipulates_source': False,
19+
'manipulates_state': False
20+
}
21+
22+
def __init__(self, phi: float = 0.125, s: float = 0.5, l: float = 3,
23+
initial: Action = C) -> None:
24+
# This Keeps track of the parameter values (phi,s,l) as well as the
25+
# four vector which makes final decisions.
26+
super().__init__()
27+
self.scores = {C: 0, D: 0}
28+
self.phi = phi
29+
self.s = s
30+
self.l = l
31+
self._initial = initial
32+
33+
def set_four_vector(self, four_vector: Tuple[float, float, float, float]):
34+
# This checks the four vector is usable and allows previous matches' output to be input for next four vector
35+
if not all(0 <= p <= 1 for p in four_vector):
36+
raise ValueError(
37+
"An element in the probability vector, {}, is not between 0 and 1.".format(str(four_vector)))
38+
self._four_vector = dict(zip([(C, C), (C, D), (D, C), (D, D)], map(float, four_vector)))
39+
self.classifier['stochastic'] = any(0 < x < 1 for x in set(four_vector))
40+
41+
def score_last_round(self, opponent: Player):
42+
# This gives the strategy the game attributes and allows the strategy to score itself properly
43+
game = self.match_attributes["game"]
44+
if len(self.history):
45+
last_round = (self.history[-1], opponent.history[-1])
46+
scores = game.score(last_round)
47+
self.scores[last_round[0]] += scores[0]
48+
49+
def strategy(self, opponent: Player) -> Action:
50+
s = self.s
51+
phi = self.phi
52+
l = self.l
53+
d = randint(0, 9) / 1000 # Selects random value to adjust s and l
54+
if self.scores[C] > self.scores[D] & len(self.history):
55+
# This checks scores to determine how to adjust s and l either up or down by d
56+
# This also checks if the length of the game is long enough to start adjusting
57+
self.l = l + d
58+
l = self.l
59+
# adjust l up
60+
self.s = s - d
61+
s = self.s
62+
# adjust s down
63+
R, P, S, T = self.match_attributes["game"].RPST()
64+
phi = self.phi
65+
s_min = - min((T - l) / (l - S), (l - S) / (T - l)) # Sets minimum for s
66+
if (l > R) or (s < s_min):
67+
# This checks that neither s nor l is leaving its range
68+
if (l > R):
69+
l = l - d
70+
self.l = (l + R) / 2
71+
l = self.l
72+
# If l would leave its range instead its distance from its max is halved
73+
if (s < s_min):
74+
s = s + d
75+
self.s = (s + s_min) / 2
76+
s = self.s
77+
# If s would leave its range instead its distance from its min is halved
78+
p1 = 1 - phi * (1 - s) * (R - l)
79+
p2 = 1 - phi * (s * (l - S) + (T - l))
80+
p3 = phi * ((l - S) + s * (T - l))
81+
p4 = phi * (1 - s) * (l - P)
82+
four_vector = [p1, p2, p3, p4]
83+
# Four vector is calculated with new parameters
84+
self.set_four_vector(four_vector)
85+
if not hasattr(self, "_four_vector"):
86+
raise ValueError("_four_vector not yet set")
87+
if len(opponent.history) == 0:
88+
return self._initial
89+
p = self._four_vector[(self.history[-1], opponent.history[-1])]
90+
return random_choice(p)
91+
else:
92+
# This adjusts s and l in the opposite direction
93+
self.l = l - d
94+
l = self.l
95+
# adjust l down
96+
self.s = s + d
97+
s = self.s
98+
# adjust s up
99+
R, P, S, T = self.match_attributes["game"].RPST()
100+
phi = self.phi
101+
if (l < P) or (s > 1):
102+
# This checks that neither s nor l is leaving its range
103+
if (l < P):
104+
l = l + d
105+
self.l = (l + P) / 2
106+
l = self.l
107+
# If l would leave its range instead its distance from its min is halved
108+
if (s > 1):
109+
s = s - d
110+
self.s = (s + 1) / 2
111+
s = self.s
112+
# If s would leave its range instead its distance from its max is halved
113+
p1 = 1 - phi * (1 - s) * (R - l)
114+
p2 = 1 - phi * (s * (l - S) + (T - l))
115+
p3 = phi * ((l - S) + s * (T - l))
116+
p4 = phi * (1 - s) * (l - P)
117+
four_vector = [p1, p2, p3, p4]
118+
# Four vector is calculated with new parameters
119+
self.set_four_vector(four_vector)
120+
if not hasattr(self, "_four_vector"):
121+
raise ValueError("_four_vector not yet set")
122+
if len(opponent.history) == 0:
123+
return self._initial
124+
p = self._four_vector[(self.history[-1], opponent.history[-1])]
125+
return random_choice(p)

axelrod/strategies/zero_determinant.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from random import randint
12
from axelrod.action import Action
3+
from axelrod.player import Player
24

35
from .memoryone import MemoryOnePlayer
46

@@ -225,3 +227,80 @@ class ZDSet2(LRPlayer):
225227

226228
def __init__(self, phi: float = 1 / 4, s: float = 0.0, l: float = 2) -> None:
227229
super().__init__(phi, s, l)
230+
231+
232+
class AdaptiveZeroDet(LRPlayer):
233+
name = 'AdaptiveZeroDet'
234+
classifier = {
235+
'memory_depth': float('inf'), # Long memory
236+
'stochastic': True,
237+
'makes_use_of': set(["game"]),
238+
'long_run_time': False,
239+
'inspects_source': False,
240+
'manipulates_source': False,
241+
'manipulates_state': False
242+
}
243+
244+
def __init__(self, phi: float = 0.125, s: float = 0.5, l: float = 3,
245+
initial: Action = C) -> None:
246+
# This Keeps track of the parameter values (phi,s,l) as well as the
247+
# four vector which makes final decisions.
248+
super().__init__(phi=phi, s=s, l=l)
249+
self._scores = {C: 0, D: 0}
250+
self._initial = initial
251+
252+
def score_last_round(self, opponent: Player):
253+
"""This gives the strategy the game attributes and allows the strategy
254+
to score itself properly."""
255+
game = self.match_attributes["game"]
256+
if len(self.history):
257+
last_round = (self.history[-1], opponent.history[-1])
258+
scores = game.score(last_round)
259+
self._scores[last_round[0]] += scores[0]
260+
261+
def _adjust_parameters(self):
262+
d = randint(0, 9) / 1000 # Selects random value to adjust s and l
263+
264+
if self._scores[C] > self._scores[D]:
265+
# This checks scores to determine how to adjust s and l either
266+
# up or down by d
267+
self.l = self.l + d
268+
self.s = self.s - d
269+
R, P, S, T = self.match_attributes["game"].RPST()
270+
l = self.l
271+
s = self.s
272+
s_min = - min((T - l) / (l - S), (l - S) / (T - l)) # Sets minimum for s
273+
if (l > R) or (s < s_min):
274+
# This checks that neither s nor l is leaving its range
275+
# If l would leave its range instead its distance from its max is halved
276+
if l > R:
277+
l = l - d
278+
self.l = (l + R) / 2
279+
# If s would leave its range instead its distance from its min is halved
280+
if s < s_min:
281+
s = s + d
282+
self.s = (s + s_min) / 2
283+
else:
284+
# This adjusts s and l in the opposite direction
285+
self.l = self.l - d
286+
self.s = self.s + d
287+
R, P, S, T = self.match_attributes["game"].RPST()
288+
l = self.l
289+
s = self.s
290+
if (l < P) or (s > 1):
291+
# This checks that neither s nor l is leaving its range
292+
if l < P:
293+
l = l + d
294+
self.l = (l + P) / 2
295+
# If l would leave its range instead its distance from its min is halved
296+
if s > 1:
297+
s = s - d
298+
self.s = (s + 1) / 2
299+
# Update the four vector for the new l and s values
300+
self.receive_match_attributes()
301+
302+
def strategy(self, opponent: Player) -> Action:
303+
if len(self.history) > 0:
304+
self.score_last_round(opponent)
305+
self._adjust_parameters()
306+
return super().strategy(opponent)

0 commit comments

Comments
 (0)