Dans ce défi, vous allez jouer au dilemme du prisonnier itéré bruyant.
Le dilemme du prisonnier est un scénario de la théorie des jeux où il y a deux joueurs, chacun avec deux options: coopérer ou faire défaut. Chaque joueur fait mieux pour lui-même s’il fait défaut que s'il coopère, mais les deux joueurs préfèrent le résultat où les deux joueurs coopèrent à celui où les deux joueurs font défaut.
Le dilemme du prisonnier itéré est le même jeu, sauf que vous jouez contre le même adversaire à plusieurs reprises et que vous savez ce que votre adversaire a joué dans le passé. Votre objectif est toujours d'accumuler le score le plus élevé pour vous-même, quel que soit le résultat de vos adversaires.
Le dilemme du prisonnier itéré bruyant introduit du bruit dans la communication. Du bruit sera introduit dans votre connaissance de ce que votre adversaire a joué dans le passé. Vous saurez également ce que vous avez fait dans le passé. Le taux de bruit est constant sur un tour contre le même adversaire, mais différent entre les tours.
Défi
Dans ce défi, vous allez écrire un programme Python 3 pour jouer le dilemme bruyant du prisonnier itéré.
Votre programme recevra trois entrées:
Vos propres mouvements, sans inversion aléatoire appliquée.
Les mouvements de votre adversaire, avec des retournements aléatoires appliqués.
Une variable d'état, qui commence par une liste vide à chaque tour et que vous pouvez modifier si vous le souhaitez. Vous pouvez l'ignorer si vous ne voulez pas l'utiliser.
Votre programme devrait sortir 'c'
coopérer ou 'd'
défecter.
Par exemple, voici un programme qui coopère si l’opposant a coopéré au moins 60% du temps dans le passé, après l’application de lancers aléatoires et pour les 10 premiers lancers:
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'
Si vous ne connaissez pas Python, écrivez votre soumission en pseudocode et une personne (moi-même ou un autre membre du site) peut créer le programme Python correspondant.
Gameplay
Le coureur du tournoi peut être trouvé ici: noisy-game . Courez noisy-game.py
pour lancer le tournoi. Je garderai ce référentiel à jour avec les nouvelles soumissions. Des exemples de programmes peuvent être trouvés dans basic.py
.
Le score global d'un programme est le total de ses scores sur 100 parties du jeu.
Une partie consiste en des confrontations à tour de rôle de chaque joueur contre chaque joueur, y compris le sien. Un match consiste en 100 rounds. Un tour consiste en 300 mouvements, chacun impliquant la sortie 'c'
ou'd'
.
Votre soumission jouera un match contre toutes les soumissions, y compris la vôtre. Chaque match comprendra 100 rounds. Au cours de chaque tour, une probabilité de retournement sera choisie uniformément de manière aléatoire [0, 0.5]
.
Chaque tour consistera en 300 mouvements. À chaque déplacement, les deux programmes recevront toutes les lectures précédentes qu'ils ont tentées et toutes les lectures précédentes que l'autre programme a effectuées après l'application des flips, ainsi qu'une variable d'état, qui est une liste modifiable que le programme peut modifier s'il le souhaite. Les programmes vont sortir leurs mouvements.
Les coups sont marqués comme suit: Si un programme joue un 'c'
, le programme adverse obtient 2 points. Si un programme joue une'd'
, ce programme gagne 1 point.
Ensuite, chaque coup est retourné indépendamment avec une probabilité égale à la probabilité de retournement et stocké pour être montré à l'adversaire.
Une fois que tous les tours ont été joués, nous additionnons le nombre de points que chaque joueur a obtenus lors de chaque match. Ensuite, nous utilisons le système de notation suivant pour calculer le score de chaque joueur pour la partie. Cette notation est effectuée une fois que toutes les confrontations sont terminées.
Notation
Nous allons utiliser la notation évolutive. Chaque programme commence avec un poids égal. Ensuite, les poids sont mis à jour comme suit, pour 100 itérations, en utilisant les totaux de points du jeu:
Le nouveau poids de chaque programme est proportionnel au produit de son poids précédent et de son total de points moyen pondéré par le poids de ses adversaires.
100 mises à jour sont appliquées et les poids finaux sont les scores de chaque programme pour cette phase du jeu.
Les scores globaux seront la somme sur 100 manches du match.
Les joueurs seront tous des réponses valables à ce défi, ainsi que six programmes de base pour nous aider à démarrer.
Mises en garde
Ne modifiez pas les entrées. Ne tentez pas d’affecter l’exécution d’un autre programme, sauf en coopérant ou en échouant. Ne faites pas de soumission sacrificielle qui tente de reconnaître une autre soumission et de bénéficier cet adversaire à ses propres frais. Les échappatoires standard sont interdites.
EDIT: Les soumissions peuvent ne pas dupliquer exactement les programmes de base ou les soumissions antérieures.
Si vous avez des questions, n'hésitez pas à les poser.
Résultats actuels
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
Résultats avec uniquement des réponses à cette question et programmes de base ignorant le jeu de l'adversaire:
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
Gagnant
Le concours restera ouvert indéfiniment, au fur et à mesure que de nouvelles soumissions seront publiées. Cependant, je vais déclarer un gagnant (accepter une réponse) sur la base des résultats 1 mois après la publication de cette question.
la source
exploit_threshold()
plusieurs fois en tant queexploit_threshold1()
, etc. et les ai ajoutés à laplayers
liste. Pourquoi ai-je des résultats très différents pour des stratégies identiques?Réponses:
Genug n'est pas genug
(pourrait aussi être appelé
enough2
oustealback
)J'ai appris que la mésange originale de deux tatouages attendait deux tats consécutifs comme des biches
tit_for_whoops
, et en effet, il semble que nous devrions pardonner et oublier (enfin, presque ...) des tats simples plus tôt. Et beaucoup de joueurs font défaut dans les derniers tours. Je préfère toujours être sympa quand tout va bien jusqu'à présent, mais la barre de tolérance du bot ne cesse de baisser.la source
Tit-For-Whoops
Inspiré par une stratégie de ncase.me/trust
Défauts seulement si l'autre joueur a fait défection deux fois de suite, pour éviter les malentendus.
la source
Changement de cœur
A un changement de coeur en cours de route. Fait étonnamment bien.
la source
Stealer de stratégie
Inspiré par Assez, change_sur_ce_cœur et se moque de qui. Devrait être un peu plus tolérant. J'ai essayé de modifier les chiffres pour obtenir les meilleurs résultats, mais ils ne voulaient pas beaucoup changer.
la source
Tit-For-Time
Si vous avez passé le plus clair de mon temps à me faire mal, je vais juste vous faire du mal en retour. Probablement.
la source
Méfiance croissante
Plus l'adversaire me trahissait, moins je pouvais croire que c'était juste du bruit.
la source
state
argument qui par défaut est une liste? Les listes sont modifiables, de sorte que l'état serait facilement modifiable.Jedi2Sith
Tout commence bien et altruiste, mais avec le temps l'influence du côté obscur devient de plus en plus forte, jusqu'au point de non retour. Il n’ya pas moyen d’arrêter cette influence, mais toutes les mauvaises choses qu’elle voit se produisent ne font que contribuer au pouvoir du côté obscur ...
Essayez-le en ligne!
la source
Curseur
Commence par «c» et glisse progressivement vers ou en dehors de «d».
la source
Stumbler Stumbler
Basé sur votre stratégie de seuil d’exploitation avec seulement des parties cohérentes gardées en trace pour permuter entre défaut et surtout coopérer
UPDATE: garde la trace de deux jeux consécutifs et de trois jeux consécutifs, punissant uniquement dans des conditions plus difficiles et ajoutant un choix aléatoire en cas de doute.
UPDATE 2: Condition supprimée et fonction de distribution ajoutée
la source
Bruit Bot
Je suis certainement coopérer bot. C'est juste du bruit.
la source
Trop c'est trop
Commence comme tit pour deux tat où les deux tat ne doivent pas être consécutifs (contrairement à
tit_for_whoops
). S'il doit jouerd
trop souvent, il passe aud
total.la source
Poisson rouge
Un poisson rouge ne pardonne jamais, mais il oublie vite.
la source
la source
Decaying Memory
Weighs recent history more. Slowly forgets the past.
la source
Kickback
Some vague ideas...
la source
Doesn't Really Get The Whole "Noise" Thing
Never forgives a traitor.
la source
sounder:
edit: added retaliation in probably low noise scenarios
basically, if all 4 first moves are cooperate, that means we should expect less noise than usual. defect a little bit every so often to make up for the less points we would get from never defecting, and have it be able to be blamed on noise. we also retaliate if they defect against us
if our opponent does a lot of defecting in those turns (2 or more) we just defect back at them. if it was just noise, the noise would affect our moves anyway.
otherwise, if only 1 move was defect, we just do simple tit for tat the rest of the game.
la source
Alternate
Picks randomly in the first round, then alternates. Always defects in the last 10 rounds.
la source
Wait for 50
After 50 defects, let 'em have it!
la source
Somehwat naive
I'll just assume that if you've defected less than the flip probability (roughly) in the last n turns, it was noise and not that you're mean!
Haven't figures out the best n, might look further into that.
la source
Every Three
Defects every three turns regardless. Also defects the last 50 turns. Also defects if his opponent defected 4 out of 5 of the last rounds.
la source
Buckets
Plays nice to begin. Looks at their last 20, if < 25% d, returns c, > 75% d, returns d, and in between chooses randomly along a linear probability function. Last 50, defects. Had this at last 10 but saw lots of last 50 defects.
First time here so let me know if something needs to be fixed (or how I can test this).
la source
players
for quick iterations.Tit-For-Stat
Defects if the opponent has defected more than half the time.
la source