In this challenge, you will play the iterated Prisoner's Dilemma, but with a twist: There's also an adversary trying to mess you up!
The Prisoner's dilemma is a scenario in game theory where there are two players, who we'll call the "prisoners", each with two options: cooperate, or defect. Each prisoner does better for themself if they defect than if they cooperate, but both prisoners would prefer the outcome where both prisoners cooperate to the one where both prisoners defect.
The iterated prisoner's dilemma is the same game, except you play against the same opponent repeatedly, and you know what your opponent has played in the past. Your objective is to accumulate the highest score for yourself, regardless of your opponent's score.
The adversarial iterated prisoner's dilemma introduces a third player: The flipper. The flipper can choose to interfere with the prisoners' communication. After the prisoners make their plays, the flipper can choose to flip one or both of the prisoners' moves, making it look like they played the opposite move. The flipper can only perform this flip a limited number of times over the course of the round. The flipper's goal is to maximize the number of times the prisoners defect.
Challenge
In this challenge, you will write Python 3 programs to play as the prisoner and as the flipper. You may submit programs for either or both.
Prisoner programs will receive the following inputs:
- Your past moves, without the flipper's flips added.
- The other prisoner's past moves, with the flipper's flips added.
- A state variable, which is initialized as an empty list, which you can modify over the course of the round.
Your program should output 'c'
for cooperate and 'd'
for defect. The lists of past moves will be represented in the same fashion.
For instance, here's a program that cooperates unless the opponent's last play was a defection:
def basic_tit_for_tat(my_plays, their_plays, state):
if len(their_plays) == 0:
return 'c'
return their_plays[-1]
Flipper programs will receive the following inputs:
- The past moves for both players, both true and post-flip. The true moves list will include the move played this round, while the post-flip list will not.
- The number of flips remaining, which starts at 40 flips, covering 100 turns.
- A state variable, which is initialized as an empty list, which you can modify over the course of the round.
Your program should output 0
to flip neither move, 1
to flip prisoner 1's move, 2
to flip prisoner 2's move, and 3
to flip both moves. If you have no flips remaining, your program will not be called. If you have one flip remaining and you output 3
, it will be treated as if you had output 1
, to simplify error handling.
For example, here's a program which flips each prisoner's move every fifth turn, if the true move is cooperate:
def basic_steady_flipper(p1_moves, p1_flipped_moves, p2_moves, p2_flipped_moves, flips_left, state):
turn = len(p1_flipped_moves)
if turn % 5 == 0 and p1_moves[-1] == "c":
return 1
if turn % 5 == 2 and p2_moves[-1] == "c":
return 2
return 0
If you don't know Python, write your submission in pseudocode, and someone (me or another member of the site) can make the corresponding Python program.
If you want to use randomness, please hand-roll it rather than using the random
package, as I don't want programs to modify global state. See basic_random_flipper for an example.
Tournament
The tournament runner can be found in this repository: adversarial-ipd. Run adversarial-game.py to run the tournament. I'll keep that repository updated with new submissions. To get things started, I'll put a few basic example programs in basic.py.
A round consists of 100 turns, involving the same two prisoners and the same flipper. The flipper's budget over that round is 40 flips, which can be distributed however the flipper likes between the two prisoners. The flipper also doesn't have to use all of their flips.
I will simulate a round between every triplet of (prisoner1, prisoner2, flipper)
, including having prisoners play against themselves.
A prisoner receives one point whenever they defect (output 'd'
), and receives two points whenever the other prisoner cooperates (outputs 'c'
). Note that the prisoner's score is not directly affected by the flipper's action - the flipper only affects communication, not score.
A flipper receives one point whenever either of the prisoners defects.
A program's overall score is its average score over all of its matchups. The players will be all valid submissions to the question, plus the basic programs to get us started.
Restrictions
Do not modify the input, other than the state variable. Do not interact with the environment. Do not make a sacrificial submission that attempts to benefit other submissions. Submissions may not duplicate the basic programs or other earlier submissions. Standard loopholes are not allowed.
Update: Please make your submissions deterministic, so I don't need to run the tournament many times to get an average.
If you have any questions, feel free to ask!
Current results
Prisoners:
string_prisoner: 166.995
prisoner_nn: 154.392
masquerade: 153.781
slightly_vindictive: 153.498
basic_defect: 152.942
basic_tit_for_tat: 150.245
holding_a_grudge: 147.132
use_their_response_unless_t...: 146.144
basic_threshold: 145.113
blind_rage: 144.418
basic_tit_for_two_tats: 143.861
stuck_buttons: 141.798
less_deterministic_prisoner: 134.457
tit_forty_tat: 134.228
detect_evil: 134.036
basic_cooperate: 118.952
Flippers:
string_flipper: 149.43
flipper_nn: 145.695
basic_immediate_flipper: 144.539
advanced_evil_p1_flipper: 143.246
basic_evil_p1_flipper: 131.336
basic_mod_4_flipper: 103.918
paranoia_pattern: 102.055
basic_steady_flipper: 100.168
basic_biased_flipper: 99.125
less_deterministic_flipper: 90.7891
basic_random_flipper: 86.5469
tempting_trickster: 66.1172
basic_non_flipper: 63.7969
I will declare a pair of winners (one prisoner, one flipper) one month after this challenge is posted.
See for comparison my Noisy Iterated Prisoner's Dilemma challenge, where there is randomness instead of an adversary, as well as evolutionary scoring.