In this challenge, you will play the noisy iterated prisoner's dilemma.
The Prisoner's dilemma is a scenario in game theory where there are two players, each with two options: cooperate, or defect. Each player does better for themself if they defect than if they cooperate, but both players would prefer the outcome where both players cooperate to the one where both players 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 always to accumulate the highest score for yourself, regardless of how your opponent does.
The noisy iterated prisoner's dilemma introduces some noise into the communication. Your knowledge of what your opponent has played in the past will have some noise introduced. You will also know what moves you made in the past. The noise rate is constant over a round against the same opponent, but different between different rounds.
In this challenge, you will write a Python 3 program to play the noisy iterated prisoner's dilemma.
Your program will receive three inputs:
Your own moves, without random flips applied.
Your opponent's moves, with random flips applied.
A state variable, which starts as an empty list each round, and which you can modify if you want. You can ignore this if you don't want to use it.
Your program should output
'c' to cooperate or
'd' to defect.
For instance, here's a program that cooperates if the opponent has cooperated at least 60% of the time in the past, after random flips were applied, and for the first 10 flips:
def threshold(my_plays, their_flipped_plays, state): if len(their_flipped_plays) < 10: return 'c' opp_c_freq = their_flipped_plays.count('c')/len(their_flipped_plays) if opp_c_freq > 0.6: return 'c' else: return 'd'
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.
A program's overall score is the total of its score over 100 plays of the game.
A game consists of round-robin matchups of each player against each player, including itself. A matchup consists of 100 rounds. A round consists of 300 moves, each of which involves outputting
Your submission will play a matchup against every submission, including your own. Each matchup will consist of 100 rounds. During each round, a flip probability will be chosen uniformly randomly from
Each round will consist of 300 moves. On each move, both programs will receive all previous plays they have attempted, and all previous plays the other program has made, after flips are applied, and a state variable, which is a mutable list which the program can modify if it wants to. The programs will output their moves.
Moves are scored as follows: If a program plays a
'c', the opposing program gets 2 points. If a program plays a
'd', that program gets 1 point.
Then, each move is flipped independently with probability equal to the flip probability, and stored for showing to the opponent.
After all of the rounds have been played, we sum the number of points each player got in each matchup. Then, we use the following scoring system to calculate each player's score for the game. This scoring is performed after all of the matchups are complete.
We will use evolutionary scoring. Each program starts with equal weight. Then, weights are updated as follows, for 100 iterations, using the point totals from the game:
Each program's new weight is proportional to the product of its previous weight and its average point total, weighted by the weights of its opponents.
100 such updates are applied, and the final weights are each program's score for that run of the game.
The overall scores will be the sum over 100 runs of the game.
The players will be all valid answers to this challenge, plus six basic programs to get us started.
Do not modify the inputs. Do not attempt to affect the execution of any other program, except via cooperating or defecting. Do not make a sacrificial submission that attempts to recognize another submission and benefit that opponent at its own expense. Standard loopholes are banned.
EDIT: Submissions may not exactly duplicate any of the basic programs or any earlier submission.
If you have any questions, feel free to ask.
nicht_genug: 40.6311 stealer: 37.1416 enough: 14.4443 wait_for_50: 6.947 threshold: 0.406784 buckets: 0.202875 change_of_heart: 0.0996783 exploit_threshold: 0.0670485 kickback: 0.0313357 tit_for_stat: 0.0141368 decaying_memory: 0.00907645 tit_for_whoops: 0.00211803 slider: 0.00167053 trickster: 0.000654875 sounder: 0.000427348 tit_for_tat: 9.12471e-05 stubborn_stumbler: 6.92879e-05 tit_for_time: 2.82541e-05 jedi2sith: 2.0768e-05 cooperate: 1.86291e-05 everyThree: 1.04843e-05 somewhat_naive: 4.46701e-06 just_noise: 1.41564e-06 growing_distrust: 5.32521e-08 goldfish: 4.28982e-09 vengeful: 2.74267e-09 defect: 3.71295e-10 alternate: 2.09372e-20 random_player: 6.74361e-21
Results with only answers to this question and basic programs that ignore the opponent's play:
nicht_genug: 39.3907 stealer: 33.7864 enough: 20.9032 wait_for_50: 5.60007 buckets: 0.174457 kickback: 0.0686975 change_of_heart: 0.027396 tit_for_stat: 0.024522 decaying_memory: 0.0193272 tit_for_whoops: 0.00284842 slider: 0.00153227 sounder: 0.000472289 trickster: 0.000297515 stubborn_stumbler: 3.76073e-05 cooperate: 3.46865e-05 tit_for_time: 2.42263e-05 everyThree: 2.06095e-05 jedi2sith: 1.62591e-05 somewhat_naive: 4.20785e-06 just_noise: 1.18372e-06 growing_distrust: 6.17619e-08 vengeful: 3.61213e-09 goldfish: 3.5746e-09 defect: 4.92581e-10 alternate: 6.96497e-20 random_player: 1.49879e-20
The competition will stay open indefinitely, as new submissions are posted. However, I will declare a winner (accept an answer) based on the results 1 month after this question was posted.