Skip to content

Commit

Permalink
Merge pull request #1126 from MHakem/add-tranquiliser
Browse files Browse the repository at this point in the history
Add Tranquilizer (K67R)
  • Loading branch information
meatballs committed Sep 3, 2017
2 parents 4ea41d0 + 1a0ab10 commit 3fd3250
Show file tree
Hide file tree
Showing 6 changed files with 387 additions and 3 deletions.
3 changes: 2 additions & 1 deletion axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .axelrod_first import (
Davis, RevisedDowning, Feld, Grofman, Nydegger, Joss, Shubik, Tullock,
UnnamedStrategy, SteinAndRapoport, TidemanAndChieruzzi)
from .axelrod_second import Champion, Eatherley, Tester, Gladstein
from .axelrod_second import Champion, Eatherley, Tester, Gladstein, Tranquilizer
from .backstabber import BackStabber, DoubleCrosser
from .better_and_better import BetterAndBetter
from .calculator import Calculator
Expand Down Expand Up @@ -253,6 +253,7 @@
TidemanAndChieruzzi,
TitForTat,
TitFor2Tats,
Tranquilizer,
TrickyCooperator,
TrickyDefector,
Tullock,
Expand Down
211 changes: 211 additions & 0 deletions axelrod/strategies/axelrod_second.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
from axelrod.player import Player
from axelrod.random_ import random_choice

from axelrod.interaction_utils import compute_final_score


C, D = Action.C, Action.D


Expand Down Expand Up @@ -199,3 +202,211 @@ def strategy(self, opponent: Player) -> Action:
else:
# Play TFT
return opponent.history[-1]

class Tranquilizer(Player):

"""
Submitted to Axelrod's second tournament by Craig Feathers
Description given in Axelrod's "More Effective Choice in the
Prisoner's Dilemma" paper: The rule normally cooperates but
is ready to defect if the other player defects too often.
Thus the rule tends to cooperate for the first dozen or two moves
if the other player is cooperating, but then it throws in a
defection. If the other player continues to cooperate, then defections
become more frequent. But as long as Tranquilizer is maintaining an
average payoff of at least 2.25 points per move, it will never defect
twice in succession and it will not defect more than
one-quarter of the time.
This implementation is based on the reverse engineering of the
Fortran strategy K67R from Axelrod's second tournament.
Reversed engineered by: Owen Campbell, Will Guo and Mansour Hakem.
The strategy starts by cooperating and has 3 states.
At the start of the strategy it updates its states:
- It counts the number of consecutive defections by the opponent.
- If it was in state 2 it moves to state 0 and calculates the
following quantities two_turns_after_good_defection_ratio and
two_turns_after_good_defection_ratio_count.
Formula for:
two_turns_after_good_defection_ratio:
self.two_turns_after_good_defection_ratio = (
((self.two_turns_after_good_defection_ratio
* self.two_turns_after_good_defection_ratio_count)
+ (3 - (3 * self.dict[opponent.history[-1]]))
+ (2 * self.dict[self.history[-1]])
- ((self.dict[opponent.history[-1]]
* self.dict[self.history[-1]])))
/ (self.two_turns_after_good_defection_ratio_count + 1)
)
two_turns_after_good_defection_ratio_count =
two_turns_after_good_defection_ratio + 1
- If it was in state 1 it moves to state 2 and calculates the
following quantities one_turn_after_good_defection_ratio and
one_turn_after_good_defection_ratio_count.
Formula for:
one_turn_after_good_defection_ratio:
self.one_turn_after_good_defection_ratio = (
((self.one_turn_after_good_defection_ratio
* self.one_turn_after_good_defection_ratio_count)
+ (3 - (3 * self.dict[opponent.history[-1]]))
+ (2 * self.dict[self.history[-1]])
- (self.dict[opponent.history[-1]]
* self.dict[self.history[-1]]))
/ (self.one_turn_after_good_defection_ratio_count + 1)
)
one_turn_after_good_defection_ratio_count:
one_turn_after_good_defection_ratio_count =
one_turn_after_good_defection_ratio + 1
If after this it is in state 1 or 2 then it cooperates.
If it is in state 0 it will potentially perform 1 of the 2
following stochastic tests:
1. If average score per turn is greater than 2.25 then it calculates a
value of probability:
probability = (
(.95 - (((self.one_turn_after_good_defection_ratio)
+ (self.two_turns_after_good_defection_ratio) - 5) / 15))
+ (1 / (((len(self.history))+1) ** 2))
- (self.dict[opponent.history[-1]] / 4)
)
and will cooperate if a random sampled number is less than that value of
probability. If it does not cooperate then the strategy moves to state 1
and defects.
2. If average score per turn is greater than 1.75 but less than 2.25
then it calculates a value of probability:
probability = (
(.25 + ((opponent.cooperations + 1) / ((len(self.history)) + 1)))
- (self.opponent_consecutive_defections * .25)
+ ((current_score[0]
- current_score[1]) / 100)
+ (4 / ((len(self.history)) + 1))
)
and will cooperate if a random sampled number is less than that value of
probability. If not, it defects.
If none of the above holds the player simply plays tit for tat.
Tranquilizer came in 27th place in Axelrod's second torunament.
Names:
- Tranquilizer: [Axelrod1980]_
"""

name = 'Tranquilizer'
classifier = {
'memory_depth': float('inf'),
'stochastic': True,
'makes_use_of': {"game"},
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def __init__(self):
super().__init__()
self.num_turns_after_good_defection = 0 # equal to FD variable
self.opponent_consecutive_defections = 0 # equal to S variable
self.one_turn_after_good_defection_ratio= 5 # equal to AD variable
self.two_turns_after_good_defection_ratio= 0 # equal to NO variable
self.one_turn_after_good_defection_ratio_count = 1 # equal to AK variable
self.two_turns_after_good_defection_ratio_count = 1 # equal to NK variable
# All above variables correspond to those in original Fotran Code
self.dict = {C: 0, D: 1}


def update_state(self, opponent):

"""
Calculates the ratio values for the one_turn_after_good_defection_ratio,
two_turns_after_good_defection_ratio and the probability values,
and sets the value of num_turns_after_good_defection.
"""
if opponent.history[-1] == D:
self.opponent_consecutive_defections += 1
else:
self.opponent_consecutive_defections = 0

if self.num_turns_after_good_defection == 2:
self.num_turns_after_good_defection = 0
self.two_turns_after_good_defection_ratio = (
((self.two_turns_after_good_defection_ratio
* self.two_turns_after_good_defection_ratio_count)
+ (3 - (3 * self.dict[opponent.history[-1]]))
+ (2 * self.dict[self.history[-1]])
- ((self.dict[opponent.history[-1]]
* self.dict[self.history[-1]])))
/ (self.two_turns_after_good_defection_ratio_count + 1)
)
self.two_turns_after_good_defection_ratio_count += 1
elif self.num_turns_after_good_defection == 1:
self.num_turns_after_good_defection = 2
self.one_turn_after_good_defection_ratio = (
((self.one_turn_after_good_defection_ratio
* self.one_turn_after_good_defection_ratio_count)
+ (3 - (3 * self.dict[opponent.history[-1]]))
+ (2 * self.dict[self.history[-1]])
- (self.dict[opponent.history[-1]]
* self.dict[self.history[-1]]))
/ (self.one_turn_after_good_defection_ratio_count + 1)
)
self.one_turn_after_good_defection_ratio_count += 1

def strategy(self, opponent: Player) -> Action:

if not self.history:
return C


self.update_state(opponent)
if self.num_turns_after_good_defection in [1, 2]:
return C

current_score = compute_final_score(zip(self.history, opponent.history))

if (current_score[0] / ((len(self.history)) + 1)) >= 2.25:
probability = (
(.95 - (((self.one_turn_after_good_defection_ratio)
+ (self.two_turns_after_good_defection_ratio) - 5) / 15))
+ (1 / (((len(self.history))+1) ** 2))
- (self.dict[opponent.history[-1]] / 4)
)
if random.random() <= probability:
return C
self.num_turns_after_good_defection = 1
return D
if (current_score[0] / ((len(self.history)) + 1)) >= 1.75:
probability = (
(.25 + ((opponent.cooperations + 1) / ((len(self.history)) + 1)))
- (self.opponent_consecutive_defections * .25)
+ ((current_score[0]
- current_score[1]) / 100)
+ (4 / ((len(self.history)) + 1))
)
if random.random() <= probability:
return C
return D
return opponent.history[-1]
Loading

0 comments on commit 3fd3250

Please sign in to comment.