Cette tâche fait partie du premier programme périodique Push Push du premier programme de programmation de premier ordre et vise à illustrer la nouvelle proposition du type défi du roi de la colline .
La tâche consiste à rédiger un programme permettant de jouer le dilemme du prisonnier réitéré mieux que les autres participants.
Regarde, Vinny. Nous connaissons votre compagnon de cellule --- comment s'appelle-t-il? Yeah McWongski, le gangster nippo-irlandais-ukrainien, prépare quelque chose et vous savez ce que c'est.
Nous essayons d'être gentil ici, Vinnie. Vous donner une chance.
Si vous nous dites ce qu'il prévoit, nous vous verrons bien travailler.
Et si vous ne le faites pas ...
Les règles du jeu
- Le concours consiste en un tour complet (toutes les paires possibles) de deux concurrents à la fois (y compris les jeux libres).
- Il y a 100 tours joués entre chaque paire
- À chaque tour, chaque joueur doit choisir entre coopérer avec l'autre joueur ou le trahir, sans connaître les intentions des autres joueurs en la matière, mais en gardant à l'esprit le résultat des précédents tours joués contre cet adversaire.
- Les points sont attribués pour chaque tour en fonction du choix combiné. Si les deux joueurs coopèrent, ils obtiennent chacun 2 points. La trahison mutuelle rapporte 1 point chacun. Dans le cas mixte, le joueur qui trahit se voit attribuer 4 points et le coopérateur est pénalisé de 1.
- Un match "officiel" ne sera disputé pas plus tôt que 10 jours après avoir posté toutes les propositions que je peux me mettre au travail et être utilisé pour sélectionner le gagnant "accepté". J'ai une boîte Mac OS 10.5, donc les solutions POSIX devraient fonctionner, mais certains linuxismes ne fonctionnent pas. De même, je n'ai pas de support pour l'API win32. Je suis disposé à faire un effort de base pour installer des choses, mais il y a une limite. Les limites de mon système ne représentent en aucun cas les limites des réponses acceptables, mais simplement celles qui seront incluses dans la correspondance "officielle".
L'interface du programmeur
- Les entrées doivent être sous la forme de programmes pouvant être exécutés à partir de la ligne de commande. la décision doit être la sortie (unique!) du programme sur la sortie standard. L'historique des tours précédents avec cet adversaire sera présenté comme un argument de ligne de commande.
- La sortie est soit "c" (pour clam up ) ou "t" (pour tout dire ).
- L'historique est constitué d'une seule chaîne de caractères représentant les tours précédents, les derniers tours apparaissant le plus tôt dans la chaîne. Les personnages sont
- "K" (pour garder la foi qui signifie coopération mutuelle)
- "R" (pour rat b @ st @ rd m'a vendu! )
- "S" (pour ventouse! Ce qui signifie que vous avez bénéficié d'une trahison)
- "E" (pour tout le monde cherche le numéro un sur la trahison mutuelle)
Le support
Quatre joueurs seront fournis par l'auteur
- Angel - coopère toujours
- Diable - parle toujours
- TitForTat - Coopère au premier tour puis fait comme il était au dernier tour
- Aléatoire - 50/50
auquel je vais ajouter toutes les entrées que je peux avoir à courir.
Le score total sera le score total contre tous les adversaires (y compris les jeux qu’il joue seul une fois et en utilisant le score moyen).
Les participants
(actuel au 2 mai 2011 7:00)
La poignée de main secrète | Missile anti-T42T | Méfiance (variante) | Anti-poignée de main | Le petit lisper | La convergence | Requin | Probabimatic | Pavlov - Gagnez le séjour, perdez le commutateur | Honneur parmi les voleurs | Aide Vampire | Druide | Petit Schemer | Bygones | Tit pour deux tatouages | Simpleton |
Buteur
#! /usr/bin/python
#
# Iterated prisoner's dilemma King of Hill Script Argument is a
# directory. We find all the executables therein, and run all possible
# binary combinations (including self-plays (which only count once!)).
#
# Author: dmckee (https://codegolf.stackexchange.com/users/78/dmckee)
#
import subprocess
import os
import sys
import random
import py_compile
###
# config
PYTHON_PATH = '/usr/bin/python' #path to python executable
RESULTS = {"cc":(2,"K"), "ct":(-1,"R"), "tc":(4,"S"), "tt":(1,"E")}
def runOne(p,h):
"""Run process p with history h and return the standard output"""
#print "Run '"+p+"' with history '"+h+"'."
process = subprocess.Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)
return process.communicate()[0]
def scoreRound(r1,r2):
return RESULTS.get(r1[0]+r2[0],0)
def runRound(p1,p2,h1,h2):
"""Run both processes, and score the results"""
r1 = runOne(p1,h1)
r2 = runOne(p2,h2)
(s1, L1), (s2, L2) = scoreRound(r1,r2), scoreRound(r2,r1)
return (s1, L1+h1), (s2, L2+h2)
def runGame(rounds,p1,p2):
sa, sd = 0, 0
ha, hd = '', ''
for a in range(0,rounds):
(na, ha), (nd, hd) = runRound(p1,p2,ha,hd)
sa += na
sd += nd
return sa, sd
def processPlayers(players):
for i,p in enumerate(players):
base,ext = os.path.splitext(p)
if ext == '.py':
py_compile.compile(p)
players[i] = '%s %sc' %( PYTHON_PATH, p)
return players
print "Finding warriors in " + sys.argv[1]
players=[sys.argv[1]+exe for exe in os.listdir(sys.argv[1]) if os.access(sys.argv[1]+exe,os.X_OK)]
players=processPlayers(players)
num_iters = 1
if len(sys.argv) == 3:
num_iters = int(sys.argv[2])
print "Running %s tournament iterations" % (num_iters)
total_scores={}
for p in players:
total_scores[p] = 0
for i in range(1,num_iters+1):
print "Tournament %s" % (i)
scores={}
for p in players:
scores[p] = 0
for i1 in range(0,len(players)):
p1=players[i1];
for i2 in range(i1,len(players)):
p2=players[i2];
# rounds = random.randint(50,200)
rounds = 100
#print "Running %s against %s (%s rounds)." %(p1,p2,rounds)
s1,s2 = runGame(rounds,p1,p2)
#print (s1, s2)
if (p1 == p2):
scores[p1] += (s1 + s2)/2
else:
scores[p1] += s1
scores[p2] += s2
players_sorted = sorted(scores,key=scores.get)
for p in players_sorted:
print (p, scores[p])
winner = max(scores, key=scores.get)
print "\tWinner is %s" %(winner)
total_scores[p] += 1
print '-'*10
print "Final Results:"
players_sorted = sorted(total_scores,key=total_scores.get)
for p in players_sorted:
print (p, total_scores[p])
winner = max(total_scores, key=total_scores.get)
print "Final Winner is " + winner
- Les plaintes concernant mon horrible python sont les bienvenues, car je suis sûr que ça craint plus d'un moyen
- Corrections de bugs bienvenues
Changelog de marqueur:
- Imprimez les joueurs et les scores triés et déclarez le gagnant (4/29, Casey)
- Vous pouvez éventuellement exécuter plusieurs tournois (
./score warriors/ num_tournaments)
) default = 1, détecter et compiler des sources Python (4/29, Casey) - Correction d'un bug particulièrement stupide dans lequel le deuxième joueur se voyait transmettre un historique incorrect. (4/30, dmckee; merci Josh)
Guerriers initiaux
A titre d'exemple, et afin que les résultats puissent être vérifiés
ange
#include <stdio.h>
int main(int argc, char**argv){
printf("c\n");
return 0;
}
ou
#!/bin/sh
echo c
ou
#!/usr/bin/python
print 'c'
Diable
#include <stdio.h>
int main(int argc, char**argv){
printf("t\n");
return 0;
}
au hasard
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char**argv){
srandom(time(0)+getpid());
printf("%c\n",(random()%2)?'c':'t');
return 0;
}
Notez que le marqueur peut ré-invoquer le guerrier plusieurs fois en une seconde, un effort sérieux doit donc être fait pour assurer le caractère aléatoire des résultats si le temps est utilisé pour ensemencer le PRNG.
TitForTat
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char**argv){
char c='c';
if (argv[1] && (
(argv[1][0] == 'R') || (argv[1][0] == 'E')
) ) c='t';
printf("%c\n",c);
return 0;
}
Le premier qui fait quelque chose avec l'histoire.
Faire fonctionner le marqueur uniquement sur les rendements fournis par les guerriers
Finding warriors in warriors/
Running warriors/angel against warriors/angel.
Running warriors/angel against warriors/devil.
Running warriors/angel against warriors/random.
Running warriors/angel against warriors/titfortat.
Running warriors/devil against warriors/devil.
Running warriors/devil against warriors/random.
Running warriors/devil against warriors/titfortat.
Running warriors/random against warriors/random.
Running warriors/random against warriors/titfortat.
Running warriors/titfortat against warriors/titfortat.
('warriors/angel', 365)
('warriors/devil', 832)
('warriors/random', 612)
('warriors/titfortat', 652)
Ce diable, il est un artisan, et les gentils gars arrivent en dernier.
Résultats
de la course "officielle"
('angel', 2068)
('helpvamp', 2295)
('pavlov', 2542)
('random', 2544)
('littleschemer', 2954)
('devil', 3356)
('simpleton', 3468)
('secrethandshake', 3488)
('antit42t', 3557)
('softmajo', 3747)
('titfor2tats', 3756)
('convergence', 3772)
('probabimatic', 3774)
('mistrust', 3788)
('hyperrationalwasp', 3828)
('bygones', 3831)
('honoramongthieves', 3851)
('titfortat', 3881)
('druid', 3921)
('littlelisper', 3984)
('shark', 4021)
('randomSucker', 4156)
('gradual', 4167)
Winner is ./gradual
la source
return (s1, L1+h1), (s2, L2+h1)
àreturn (s1, L1+h1), (s2, L2+h2)
[NoteL2+h2
au lieu deL2+h1
à la fin]? // Erreur couper-coller ou quelque chose d'aussi idiot. Sheesh!Réponses:
Graduel
Cette stratégie est basée sur un article de Beaufils, Delahaye et Mathieu . Mon C n'est vraiment pas le meilleur, alors si quelqu'un a des suggestions pour améliorer / accélérer le code, faites-le moi savoir!
[Edit] Il est intéressant de noter que Gradual a été conçu pour être une stratégie qui surpasse Tit pour Tat. Il a des propriétés similaires en ce sens qu’il est disposé à coopérer et à exercer des représailles contre un adversaire défaillant. Contrairement à Tit pour Tat, qui ne garde que le souvenir du dernier round joué, Gradual se souviendra de l’interaction complète et du nombre de fois où l’adversaire a fait défection. Il offrira cependant une coopération mutuelle par la suite.
Comme d’habitude, la performance de la stratégie dépend un peu de l’alignement d’autres stratégies. De plus, le document original n'était pas vraiment clair sur certains détails.
la source
La poignée de main secrète
La stratégie consiste ici à sacrifier les 10 premiers tours pour effectuer une poignée de main "secrète". Si je suis en cellule avec moi-même, je reconnais ensuite l'historique des 10 premiers mouvements et je mets ma casquette Angel pour le reste de la partie. Dès que je reconnais que mon compagnon de cellule n'est pas moi-même, je me transforme en démon pour tenter de tirer profit de compagnons de cellule trop coopératifs.
Le fait de sacrifier les 10 premiers tours me permettra de vaincre le diable lui-même, cela dépendra beaucoup du nombre d'entrées. Pour minimiser les dégâts, seulement 3 coopèrent apparaissent dans la poignée de main.
Edit: TAGMATCH dynamique maintenant pour éviter les erreurs stupides comme changer une seule d’entre elles afin que je puisse rendre TAG dynamique à un moment donné dans l’avenir.
Edit 2: Maintenant, génère de manière aléatoire la balise lors de la première exécution et la stocke dans le fichier spécifié par
sys.argv[0]
(.pyc
remplacé par.py
ainsi, il passe au code, pas au bytecode, fichier). Je pense que c’est la seule information disponible dans toutes mes instances que personne d’autre, ce qui semble être la seule option pour éviter les parasites.la source
TAG
qu'on jouait à l'envers. Cependant, ne devriez-vous pasTAGMATCH
être 'KEEEKEEEKE'?"".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
.py
votre code dans tous les fichiers et extraire le TAG. Je ne ferai pas ça en C, cependant ...Le petit lisper
Le diable
Considérez ce qui suit, format (Player1, Player2)
En supposant que P2 soit le diable, il ne peut en aucun cas perdre des points. En fait, le pire qu'il puisse faire est de gagner un seul point. Par conséquent, le pire score possible du diable sera exactement (5/2) * n, où n est le nombre de "parties" jouées. Son pire cas absolu est contre lui-même, où son score sera n, et son meilleur cas est contre un ange, qui sera 4 * n
Assert: optimal_strat = diable
c'est un tournoi. Dénoncer mon compagnon de cellule est une stratégie bien meilleure que la coopération car elle aide davantage MY SCORE (+4). BONUS - il est critiqué (-1)! Si je lui colle la tête, je peux gagner (+2) et perdre (-1). Ainsi, les coups de poignard sont statistiquement récompensés.
Mais est-ce optimal?
Il n’ya aucune raison de JAMAIS (dans le cadre de ce système de notation) de coopérer.
Dans le système KOTH, la maximisation des rendements est essentielle. Même si deux de vos robots sont parfaitement synchronisés et coopèrent parfaitement, leurs scores individuels ne seront encore améliorés que de 200 points pour leur esprit sportif. Un démon, par contre, gagnera au moins 100 points, avec une moyenne de 200 cas et un maximum de 400, et coûtera à ses adversaires jusqu’à 100 points! Donc, pratiquement, le diable marque vraiment un jeu moyen de 300, passant à 500.
Conclusion - le temps nous le dira
Pour moi, il semble que la notation devrait être réexaminée de peur que le diable prenne la journée. Augmenter le score de coopération à 3 pourrait le faire. Il est toutefois possible de détecter les diables et de les empêcher de marquer 400 fois leur victoire, comme le montrent les pavlov et les dépit. Puis-je prouver que l'un ou l'autre ramassera suffisamment de points pour que sa coopération justifie sa foi? non. Tout cela dépend du dernier groupe de prétendants.
Et s'il vous plaît faites votre pire à ce post. Je veux écrire mon article principal à ce sujet quand tout sera fini.
Historique de la version
VERSION OFFICIELLE DE LISPER
Version de développement de LISPER
la source
fink install clisp
:: tapoter plusieurs fois ::There is no reason to EVER (under this scoring system) co-operate
est seulement à moitié correct. Si vous savez que votre adversaire ne tient pas compte de l'historique (ange, diable, aléatoire), vous devriez toujours faire défection. Si votre adversaire prend en compte l'historique et que vous pouvez synchroniser, vous pourrez faire mieux. J'ai quelques idées qui visent à déterminer si l'adversaire est rationnel ou supranational.(random 20)
donne 2, 5 ou 8,(/ (+1 rand-num) 10)
est égal à 0,3, 0,6, 0,9 et le reste de la division avec 0,3 est 0; donc(floor *dbag* *margin*)
meurt.Méfiance (variante)
Celui-ci a été publié pour la première fois lors de mes propres tests il y a quelques années (à l'époque, j'étais en 11e année et j'ai fait une thèse minuscule sur ce sujet, en utilisant également des stratégies conçues par d'autres étudiants). Il commence par la séquence
tcc
(et joue ensuite comme Tit pour Tat.Toutes mes excuses pour l'horrible code; si quelqu'un peut raccourcir le temps sans le jouer, je vous en serais reconnaissant :-)
la source
case 1: case2: printf(...); break;
. Et gcc veut une déclaration explicite d’string.h
utiliserstrlen
. En tout cas je l'ai en cours d'exécution.Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)
quandh = ''
. Je devineargc=1
.Missile anti-T42T
Fait raisonnablement bien contre le groupe de base de guerriers: tue Angel, légèrement battu par Devil (mais garde son score bas), bat généralement facilement RAND et bat à peine Bat pour Tat. Fait mal en jouant contre lui-même.
la source
Convergence
Au départ sympa, puis joue au hasard avec un oeil sur l’histoire de l’adversaire.
J'ai essayé de réduire la pondération de l'historique, mais je ne l'ai pas correctement optimisée.
la source
Requin
Fait assez bien contre la liste de base.
la source
Pavlov - Gagnez séjour, perdez commutateur
Au premier tour, il coopère, et ensuite, si et seulement si les deux joueurs optent pour le même choix lors du coup précédent.
la source
hist[0]
(hist[-1]
est toujours le premier coup du tour)?Honneur parmi les voleurs
Notez qu’il
THIEVES_CANT
s’agit essentiellement d’une poignée de main, bien qu’elle n’émerge que lorsqu’on joue contre un coopérateur. Cependant, cela évite le problème parasite en recherchant des croisements ultérieurs. Fait assez bien contre la liste de base.la source
"Probabimatic"
Commence par coopérer, puis choisit l'option qui lui donne la valeur attendue la plus élevée. Simple.
Utilisé pour commencer par coopérer, il semble maintenant que la défection fonctionne mieux. EDIT: Oh, attendez, ce n'est pas le cas.
la source
for (char c = *str;
àchar c; for (c = *str;
alors gcc compilera ceci sans se plaindre de le mettre en mode C99.Guêpe Hyperrational
Implémenté en Java parce que je n’étais pas sûr de la complexité des structures de données. Si cela pose un problème à quelqu'un, je pense que je peux le porter en bash sans trop de problèmes, car à la fin, il n'utilise que de simples tableaux associatifs.
Remarque : j'ai retiré cette information d'un package correspondant à la dernière version de mon correctif pour permettre à l'auteur du traitement de gérer Java. Si vous souhaitez publier une solution Java utilisant des classes internes, vous devez appliquer un correctif au correctif.
Les modifications que j'ai apportées au marqueur pour exécuter ceci sont:
Merci à @rmckenzie pour avoir intégré ma fonction challenger.
la source
Exception in thread "main" java.lang.NoClassDefFoundError: //warriors/HyperrationalWasp Caused by: java.lang.ClassNotFoundException: ..warriors.HyperrationalWasp at java.net.URLClassLoader$1.run(URLClassLoader.java:217) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:205) at java.lang.ClassLoader.loadClass(ClassLoader.java:321) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Soft_majo
Eh bien, une autre des stratégies standard, juste pour compléter la liste.
Celui-ci choisit le coup que l'adversaire a le plus fait; si égal il coopère.
la source
Ventouse aléatoire
Celui-ci fera défaut si l'adversaire fait trop souvent défaut (seuil), mais essaiera au hasard d'essayer de temps en temps de poignarder.
Fait assez bien contre tout le monde sauf les lecteurs Java et Lisp (que je ne peux pas exécuter, car Java et Lisp ne sont pas sur la machine de test); la plupart du temps au moins.
la source
BYGONES
Je n'ai pas encore trouvé le meilleur rapport qualité-prix
bygones
. Je ne m'attends pas à ce que cette stratégie soit gagnante , mais je m'intéresse à la performance d'une stratégie qui ressemble à ce que je pense de "bien" dans la vie réelle. Une révision future peut également inclure la vérification du nombre de défections mutuelles.la source
Aide Vampire
A un résultat amusant et asymétrique lorsqu'il est piqué contre lui-même. Si seulement cette solution pouvait être appliquée dans la vie réelle.
la source
Druide
Fait raisonnablement bien contre la liste de base.
la source
Niais
Est-ce que ça va contre l'alignement de la base?
la source
Petit Schemer
Fait mal contre la base, mais assez bien contre la cible. De toute évidence, pas écrit dans Scheme.
la source
Tit pour deux tatouages
un autre vieux favori
la source
sys.exit(0)
? Ou laissez-le simplement finir. Edit: De même, la première invocation de votre programme est sans aucun historique, ce qui entraîne uneIndexError
perte de tempsargv[1]
.len(history)<2
article, car ce dernier ressemble à laelse
partie.return
surtout!