-
Notifications
You must be signed in to change notification settings - Fork 268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
issue#844 backstabber.py #924
Changes from all commits
d447b0b
ea05b78
8385eef
54c4099
f394247
a240da1
3d3a27c
5d74154
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,52 +17,81 @@ class BackStabber(Player): | |
classifier = { | ||
'memory_depth': float('inf'), | ||
'stochastic': False, | ||
'makes_use_of': set(['length']), | ||
'makes_use_of': {'length'}, | ||
'long_run_time': False, | ||
'inspects_source': False, | ||
'manipulates_source': False, | ||
'manipulates_state': False | ||
} | ||
|
||
@staticmethod | ||
def strategy(opponent: Player) -> Action: | ||
if not opponent.history: | ||
return C | ||
if opponent.defections > 3: | ||
return D | ||
return C | ||
def strategy(self, opponent: Player) -> Action: | ||
return _backstabber_strategy(opponent) | ||
|
||
|
||
@FinalTransformer((D, D), name_prefix=None) # End with two defections | ||
@FinalTransformer((D, D), name_prefix=None) # End with two defections | ||
class DoubleCrosser(Player): | ||
""" | ||
Forgives the first 3 defections but on the fourth | ||
will defect forever. If the opponent did not defect | ||
in the first 6 rounds the player will cooperate until | ||
the 180th round. Defects on the last 2 rounds unconditionally. | ||
will defect forever. Defects on the last 2 rounds unconditionally. | ||
|
||
If 8 <= current round <= 180, | ||
if the opponent did not defect in the first 7 rounds, | ||
the player will only defect after the opponent has defected twice in-a-row. | ||
""" | ||
|
||
name = 'DoubleCrosser' | ||
classifier = { | ||
'memory_depth': float('inf'), | ||
'stochastic': False, | ||
'makes_use_of': set(['length']), | ||
'makes_use_of': {'length'}, | ||
'long_run_time': False, | ||
'inspects_source': False, | ||
'manipulates_source': False, | ||
'manipulates_state': False | ||
} | ||
|
||
def strategy(self, opponent: Player) -> Action: | ||
cutoff = 6 | ||
|
||
if not opponent.history: | ||
return C | ||
if len(opponent.history) < 180: | ||
if len(opponent.history) > cutoff: | ||
if D not in opponent.history[:cutoff + 1]: | ||
if opponent.history[-2:] != [D, D]: # Fail safe | ||
return C | ||
if opponent.defections > 3: | ||
return D | ||
if _opponent_triggers_alt_strategy(opponent): | ||
return _alt_strategy(opponent) | ||
return _backstabber_strategy(opponent) | ||
|
||
|
||
def _backstabber_strategy(opponent: Player) -> Action: | ||
""" | ||
Cooperates until opponent defects a total of four times, then always defects. | ||
""" | ||
if not opponent.history: | ||
return C | ||
if opponent.defections > 3: | ||
return D | ||
return C | ||
|
||
|
||
def _alt_strategy(opponent: Player) -> Action: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you write specific tests for these module functions please. The don't need to be extensive but just enough so that they'd fail if something got refactored in the strategy methods removing the need for them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually. this brings up a problem i had, to which module methods was the most expedient solution. as i see it, these should all be private methods of their classes and DoubleCrosser should inherit from BackStabber. The tests, as they are, should fully cover all those methods (i don't have a coverage tool, but i think i got it). I originally wrote There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that aside, will write tests for module as is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. errrr. i hope complete tests is ok. trying to write non-complete tests is, for me, like not completing a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha, this is way more than I was expecting but it looks good to me :) |
||
""" | ||
If opponent's previous two plays were defect, then defects on next round. Otherwise, cooperates. | ||
""" | ||
previous_two_plays = opponent.history[-2:] | ||
if previous_two_plays == [D, D]: | ||
return D | ||
return C | ||
|
||
|
||
def _opponent_triggers_alt_strategy(opponent: Player) -> bool: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @uglyfruitcake is this correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes that looks good to me. |
||
""" | ||
If opponent did not defect in first 7 rounds and the current round is from 8 to 180, return True. | ||
Else, return False. | ||
""" | ||
before_alt_strategy = first_n_rounds = 7 | ||
last_round_of_alt_strategy = 180 | ||
if _opponent_defected_in_first_n_rounds(opponent, first_n_rounds): | ||
return False | ||
current_round = len(opponent.history) + 1 | ||
return before_alt_strategy < current_round <= last_round_of_alt_strategy | ||
|
||
|
||
def _opponent_defected_in_first_n_rounds(opponent: Player, first_n_rounds: int) -> bool: | ||
""" | ||
If opponent defected in the first N rounds, return True. Else return False. | ||
""" | ||
return D in opponent.history[:first_n_rounds] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here's the off-by-one. It should only check for defection in the first 6, but opponent.history[:cutoff +1] is the first 7.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, looks like you are right to me. Would be good to have @uglyfruitcake's thoughts on this PR too :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the code doesn't match the documentation, however, It's the documentation that's wrong. I spent ages optimises the numbers in Doublecrosser to get it to perform optimally and its current state will be it's optimal performance. When I wrote the description I will have put the wrong number of turns and so it should say "the first 7 rounds". It is a mistake but its wrong in the documentation not the code. Sorry!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewriting that now. in a moment, comments and tests should follow the specs.