Skip to content

Commit be2c4b0

Browse files
authored
Merge pull request #1145 from gaffney2010/master
Implemented Weiner, k41r from Axelrod's Second
2 parents 4b8616f + a2e8747 commit be2c4b0

File tree

5 files changed

+173
-4
lines changed

5 files changed

+173
-4
lines changed

axelrod/strategies/_strategies.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi)
1010
from .axelrod_second import (
1111
Champion, Eatherley, Tester, Gladstein, Tranquilizer, MoreGrofman,
12-
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen)
12+
Kluepfel, Borufsen, Cave, WmAdams, GraaskampKatzen, Weiner)
1313
from .backstabber import BackStabber, DoubleCrosser
1414
from .better_and_better import BetterAndBetter
1515
from .bush_mosteller import BushMosteller
@@ -270,6 +270,7 @@
270270
Tullock,
271271
TwoTitsForTat,
272272
VeryBad,
273+
Weiner,
273274
Willing,
274275
Winner12,
275276
Winner21,

axelrod/strategies/axelrod_second.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ def strategy(self, opponent: Player) -> Action:
762762

763763
number_defects = opponent.defections
764764
perc_defects = number_defects / turn
765+
765766
# Defect if the opponent has defected often or appears random.
766767
if turn > 39 and perc_defects > 0.39:
767768
return D
@@ -812,11 +813,13 @@ def strategy(self, opponent: Player) -> Action:
812813
if opponent.history[0] == D:
813814
number_defects -= 1
814815

815-
if number_defects in [4, 7, 9]: return D
816+
if number_defects in [4, 7, 9]:
817+
return D
816818
if number_defects > 9 and opponent.history[-1] == D:
817819
return random_choice((0.5) ** (number_defects - 9))
818820
return C
819821

822+
820823
class GraaskampKatzen(Player):
821824
"""
822825
Strategy submitted to Axelrod's second tournament by Jim Graaskamp and Ken
@@ -880,3 +883,95 @@ def strategy(self, opponent: Player) -> Action:
880883
return D
881884

882885
return opponent.history[-1] # Tit-for-Tat
886+
887+
888+
class Weiner(Player):
889+
"""
890+
Strategy submitted to Axelrod's second tournament by Herb Weiner (K41R),
891+
and came in seventh in that tournament.
892+
893+
Play Tit-for-Tat with a chance for forgiveness and a defective override.
894+
895+
The chance for forgiveness happens only if `forgive_flag` is raised
896+
(flag discussed below). If raised and `turn` is greater than `grudge`,
897+
then override Tit-for-Tat with Cooperation. `grudge` is a variable that
898+
starts at 0 and increments 20 with each forgiven Defect (a Defect that is
899+
overriden through the forgiveness logic). `forgive_flag` is lower whether
900+
logic is overriden or not.
901+
902+
The variable `defect_padding` increments with each opponent Defect, but
903+
resets to zero with each opponent Cooperate (or `forgive_flag` lowering) so
904+
that it roughly counts Defects between Cooperates. Whenever the opponent
905+
Cooperates, if `defect_padding` (before reseting) is odd, then we raise
906+
`forgive_flag` for next turn.
907+
908+
Finally a defective override is assessed after forgiveness. If five or
909+
more of the opponent's last twelve actions are Defects, then Defect. This
910+
will overrule a forgiveness, but doesn't undo the lowering of
911+
`forgiveness_flag`. Note that "last twelve actions" doesn't count the most
912+
recent action. Actually the original code updates history after checking
913+
for defect override.
914+
915+
Names:
916+
917+
- Weiner: [Axelrod1980b]_
918+
"""
919+
920+
name = "Weiner"
921+
classifier = {
922+
'memory_depth': float('inf'),
923+
'stochastic': False,
924+
'makes_use_of': set(),
925+
'long_run_time': False,
926+
'inspects_source': False,
927+
'manipulates_source': False,
928+
'manipulates_state': False
929+
}
930+
931+
def __init__(self):
932+
super().__init__()
933+
self.forgive_flag = False
934+
self.grudge = 0
935+
self.defect_padding = 0
936+
self.last_twelve = [0] * 12
937+
self.lt_index = 0 # Circles around last_twelve
938+
939+
def try_return(self, to_return):
940+
"""
941+
We put the logic here to check for the defective override.
942+
"""
943+
944+
if np.sum(self.last_twelve) >= 5:
945+
return D
946+
return to_return
947+
948+
def strategy(self, opponent: Player) -> Action:
949+
if len(opponent.history) == 0:
950+
return C
951+
952+
# Update history, lag 1.
953+
if len(opponent.history) >= 2:
954+
self.last_twelve[self.lt_index] = 0
955+
if opponent.history[-2] == D:
956+
self.last_twelve[self.lt_index] = 1
957+
self.lt_index = (self.lt_index + 1) % 12
958+
959+
if self.forgive_flag:
960+
self.forgive_flag = False
961+
self.defect_padding = 0
962+
if self.grudge < len(self.history) + 1 and opponent.history[-1] == D:
963+
# Then override
964+
self.grudge += 20
965+
return self.try_return(C)
966+
else:
967+
return self.try_return(opponent.history[-1])
968+
else:
969+
# See if forgive_flag should be raised
970+
if opponent.history[-1] == D:
971+
self.defect_padding += 1
972+
else:
973+
if self.defect_padding % 2 == 1:
974+
self.forgive_flag = True
975+
self.defect_padding = 0
976+
977+
return self.try_return(opponent.history[-1])

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ def test_strategy(self):
407407
(C, D), (C, D), (C, D), (D, D), (D, C)]
408408
self.versus_test(opponent, expected_actions=actions)
409409

410+
410411
class TestKluepfel(TestPlayer):
411412
name = "Kluepfel"
412413
player = axelrod.Kluepfel
@@ -453,6 +454,7 @@ def test_strategy(self):
453454
(D, C), (D, D)]
454455
self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=10)
455456

457+
456458
class TestBorufsen(TestPlayer):
457459
name = "Borufsen"
458460
player = axelrod.Borufsen
@@ -497,6 +499,7 @@ def test_strategy(self):
497499
[(D, C)] * 25
498500
self.versus_test(axelrod.WinShiftLoseStay(D), expected_actions=actions)
499501

502+
500503
class TestCave(TestPlayer):
501504
name = "Cave"
502505
player = axelrod.Cave
@@ -546,6 +549,7 @@ def test_strategy(self):
546549
actions += [(D, D), (D, C)] * 100 # Random finally detected
547550
self.versus_test(axelrod.Alternator(), expected_actions=actions, seed=2)
548551

552+
549553
class TestWmAdams(TestPlayer):
550554
name = "WmAdams"
551555
player = axelrod.WmAdams
@@ -586,6 +590,7 @@ def test_strategy(self):
586590
actions += [(C, C)] * 99
587591
self.versus_test(changed_man, expected_actions=actions, seed=1)
588592

593+
589594
class TestGraaskampKatzen(TestPlayer):
590595
name = "GraaskampKatzen"
591596
player = axelrod.GraaskampKatzen
@@ -621,3 +626,71 @@ def test_strategy(self):
621626
actions += [(D, C)]
622627
actions += [(D, D), (D, D), (D, C)] * 20 # Defect here on
623628
self.versus_test(Delayed_GK_Foil, expected_actions=actions)
629+
630+
631+
class TestWeiner(TestPlayer):
632+
name = "Weiner"
633+
player = axelrod.Weiner
634+
expected_classifier = {
635+
'memory_depth': float('inf'),
636+
'stochastic': False,
637+
'makes_use_of': set(),
638+
'long_run_time': False,
639+
'inspects_source': False,
640+
'manipulates_source': False,
641+
'manipulates_state': False
642+
}
643+
644+
def test_strategy(self):
645+
actions = [(C, C)] * 100 # Cooperate forever
646+
self.versus_test(axelrod.Cooperator(), expected_actions=actions)
647+
648+
actions = [(C, C)]
649+
actions += [(C, D), (D, C)] # Tit-for-Tat
650+
# Opponent's last move was a C with 1 D between
651+
actions += [(C, D)] # Tit-for-Tat. Raise forgiveness flag.
652+
actions += [(C, C)] # Tit-for-Tat. Use forgiveness flag.
653+
# Opponent's last move was a C, but defect_padding counted as 0.
654+
actions += [(C, D), (D, C)] # Tit-for-Tat
655+
# Opponent's last move was a C with 1 D between
656+
actions += [(C, D)] # Tit-for-Tat. Raise forgiveness flag.
657+
actions += [(D, C)] # Tit-for-Tat. Try forgiveness flag.
658+
# This time grudge=20, so the forgiveness flag doesn't work.
659+
actions += [(C, D)] # Tit-for-Tat.
660+
# This is the 5th opponent defect, won't be counted for 2 turns
661+
actions += [(D, C)] # Tit-for-Tat.
662+
actions += [(D, D), (D, C)] * 100 # Defect now on.
663+
self.versus_test(axelrod.Alternator(), expected_actions=actions)
664+
665+
# Build an opponent that will cause a wasted flag.
666+
opponent_actions = [C, D, C, C, C, C, D, D]
667+
Flag_Waster_1 = axelrod.MockPlayer(actions=opponent_actions)
668+
actions = [(C, C), (C, D), (D, C)]
669+
actions += [(C, C)] # Raise flag, like in Alternator
670+
actions += [(C, C)] # Use flag, but don't change outcome
671+
actions += [(C, C)]
672+
actions += [(C, D)] # Don't raise flag
673+
actions += [(D, D)] # Don't use flag
674+
self.versus_test(Flag_Waster_1, expected_actions=actions)
675+
676+
# Demonstrate that grudge is not incremented on wasted flag.
677+
opponent_actions = [C, D, C, C, C, C, D, C, D, C]
678+
Flag_Waster_2 = axelrod.MockPlayer(actions=opponent_actions)
679+
actions = [(C, C), (C, D), (D, C)]
680+
actions += [(C, C)] # Raise flag, like in Alternator
681+
actions += [(C, C)] # Use flag, but don't change outcome
682+
actions += [(C, C), (C, D), (D, C)]
683+
actions += [(C, D)] # Raise flag
684+
actions += [(C, C)] # Use flag to change outcome
685+
self.versus_test(Flag_Waster_2, expected_actions=actions)
686+
687+
# Show grudge passing over time
688+
opponent_actions = [C, D, C, D, C] + [C] * 11 + [C, D, C, D, C]
689+
Time_Passer = axelrod.MockPlayer(actions=opponent_actions)
690+
actions = [(C, C), (C, D), (D, C)]
691+
actions += [(C, D)] # Raise flag
692+
actions += [(C, C)] # Use flag to change outcome
693+
actions += [(C, C)] * 11
694+
actions += [(C, C), (C, D), (D, C)]
695+
actions += [(C, D)] # Raise flag
696+
actions += [(C, C)] # Use flag to change outcome

axelrod/tests/strategies/test_meta.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ def test_strategy(self):
335335
self.versus_test(opponent=axelrod.Alternator(),
336336
expected_actions=actions, seed=0)
337337

338-
actions = [(C, C), (C, D), (C, C), (C, D), (D, C)]
338+
actions = [(C, C), (C, D), (D, C), (C, D), (D, C)]
339339
self.versus_test(opponent=axelrod.Alternator(),
340340
expected_actions=actions, seed=1)
341341

docs/reference/overview_of_strategies.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ repository.
111111
"K38R_", "Nelson Weiderman", "Not Implemented"
112112
"K39R_", "Tom Almy", "Not Implemented"
113113
"K40R_", "Robert Adams", "Not Implemented"
114-
"K41R_", "Herb Weiner", "Not Implemented"
114+
"K41R_", "Herb Weiner", ":class:`Weiner <axelrod.strategies.axelrod_second.Weiner>`"
115115
"K42R_", "Otto Borufsen", ":class:`Borufsen <axelrod.strategies.axelrod_second.Borufsen>`"
116116
"K43R_", "R D Anderson", "Not Implemented"
117117
"K44R_", "William Adams", ":class:`WmAdams <axelrod.strategies.axelrod_second.WmAdams>`"

0 commit comments

Comments
 (0)