1P5: dilemme du prisonnier itéré

35

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 .

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
dmckee
la source
2
Si mon compagnon de cellule est nippo-irlandais-ukrainien, pourquoi son nom a-t-il l'air hiberno-sino-russe?
Peter Taylor
2
@Peter: LOL. La vérité? Eh bien, (1) les généalogies ne sont pas claires, mais je viens probablement de mon côté par l’intermédiaire du Scotch-Irish; (2) après avoir écrit "Nippo", j'ai essayé divers noms de mes amis du pays du soleil levant et n'ai pas aimé la manière dont ils ont été numérisés. J'ai donc utilisé un nom de famille chinois qui semblait être bien à la place, et (3) je ne saurais pas la différence s’ils se battaient à tour de rôle avec des fers à pneus. Ce qui semble probable dans les circonstances.
dmckee
1
@ Josh: Serait-il simple de passer return (s1, L1+h1), (s2, L2+h1)à return (s1, L1+h1), (s2, L2+h2)[Note L2+h2au lieu de L2+h1à la fin]? // Erreur couper-coller ou quelque chose d'aussi idiot. Sheesh!
dmckee
2
J'ai passé un peu de temps sur le script de test et je suis heureux d'annoncer une mise à jour ici . Cette mise à jour ajoute un shell simple au script de test, ce qui permet à l'utilisateur de lancer manuellement ce bot contre ce bot, d'organiser des tournois avec des champs restreints et d'autres éléments intéressants. N'hésitez pas à faire des suggestions! Oh. Et je dois @josh pour l'idée bot-vs-bot. C'est vraiment juste une implémentation plus sophistiquée de son script "trainer".
arrdem
2
Intéressant: il y avait 23 concurrents, chacun a donc joué 22 tours. Si tout le monde avait joué à "Angel", chaque score aurait été de 4400, mais même le meilleur score de 4167 ne correspondait pas à cela. Si seulement nous vivions dans un monde parfait ... :)
Briguy37

Réponses:

11

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.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[]) {
    if(argc == 1){
        printf("c\n");
        return 0;
    }

    size_t l = strlen(argv[1]);
    int i;
    size_t currentSequence = 0;
    size_t totalDefects = 0;
    size_t lastDefects = 0;

    for(i = l-1; i >= 0; i--){
        if(argv[1][i] == 'E' || argv[1][i] == 'R'){
            totalDefects++;
            currentSequence = 0;
        } else if(argv[1][i] == 'S') {
            currentSequence++;
        }
    }

    if(currentSequence < totalDefects)
        // continue defect sequence
        printf("t\n");
    else if(argv[1][0] == 'S' || argv[1][0] == 'E' ||
            argv[1][1] == 'S' || argv[1][1] == 'E')
        // blind cooperation
        printf("c\n");
    else if(argv[1][0] == 'R')
        // start new defect sequence
        printf("t\n");
    else
        printf("c\n");

    return 0;
}
Ventero
la source
11

La poignée de main secrète

#!/usr/bin/python
import sys
import random

def main():
    if len(sys.argv) == 1:
        hist = ""
    else:
        hist = sys.argv[1]
    if len(hist) <= len(TAG) and hist == TAGMATCH[len(TAG) - len(hist):]:
        print TAG[len(TAG) - len(hist) - 1]
        return
    if hist[-len(TAG):] == TAGMATCH:
        print 'c'
        return
    print "t"

def getTag():
    global TAG
    filename = sys.argv[0]
    filename = filename.replace(".pyc", ".py")
    f = open(filename, 'r')
    code = f.read().split('\n')
    f.close()
    if len(code[1]) == 0 or code[1][0] != '#':
        random.seed()
        newtag = 't' * 10
        cs = 0
        while cs < 3:
            pos = random.randint(0, 8)
            if newtag[pos] == 't':
                newtag = newtag[:pos] + 'c' + newtag[pos+1:]
                cs += 1
        code.insert(1, '#%s' % newtag)
        f = open(filename, 'w')
        f.write('\n'.join(code))
        f.close()
        TAG = newtag
    else:
        TAG = code[1][1:]
    global TAGMATCH
    TAGMATCH = TAG.replace('c', 'K').replace('t', 'E')

if __name__ == "__main__":
    getTag()
    main()

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]( .pycremplacé par .pyainsi, 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.

Aaron Dufour
la source
Mais comment votre doppelganger sait-il se faire démon?
arrdem
1
(Je me sens comme un perroquet, disant tout le temps "Tit pour Tat" ...) Notez que T4T battra votre stratégie dans une paire contre: T4T (coopère plus tôt) et Devil (moins de résultats de Rat), et sera en lien avec votre stratégie. Bien entendu, c'est le total général, et non le total d'appariement, qui compte à la fin. Comme vous le dites, la population est importante.
Josh Caswell
1
Oh, non, vous obtenez un S supplémentaire de Tit pour Tat. Agréable. Je n'avais pas réalisé TAGqu'on jouait à l'envers. Cependant, ne devriez-vous pas TAGMATCHêtre 'KEEEKEEEKE'? "".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
Josh Caswell
@ John Bon point - j'avais à l'origine un TAG différent et lorsque je l'ai modifié pour minimiser la coopération, j'ai oublié de mettre à jour TAGMATCH. @Arrdem L'idée est que si je joue contre moi-même, la meilleure chose à faire est que les deux coopèrent tout le temps pour maximiser la somme de leurs scores.
Aaron Dufour
1
Aww, bon sang. Alors maintenant, je dois rechercher .pyvotre code dans tous les fichiers et extraire le TAG. Je ne ferai pas ça en C, cependant ...
Joey,
6

Le petit lisper

(setf *margin* (/ (+ 40 (random 11)) 100))
(setf *r* 0.0)
(setf *s* 0.0)
(setf *k* 0.0)
(setf *e* 0.0)

;; step 1 - cout up all the games results

(loop for i from 1 to (length(car *args*)) do
    (setf foo (char (car *args*) (1- i)))
    (cond 
        ((equal foo #\R) (setf *r* (1+ *r*)))
        ((equal foo #\S) (setf *s* (1+ *s*)))
        ((equal foo #\K) (setf *k* (1+ *k*)))
        ((equal foo #\E) (setf *e* (1+ *e*)))
    )
)

(setf *sum* (+ *r* *s* *k* *e*))

;; step 2 - rate trustworthiness
(if (> *sum* 0)
    (progn
        (setf *dbag* (/ (+ *r* *e*) *sum*)) ; percentage chance he rats
        (setf *trust* (/ (+ *s* *k*) *sum*)); percentage chance he clams
    )
    (progn
        (setf *dbag* 0) ; percentage chance he rats
        (setf *trust* 0); percentage chance he clams
    )
)



;; step 3 - make a decision (the hard part....)

(write-char
    (cond
        ((> *sum* 3) (cond 
                    ((or (= *dbag* 1) (= *trust* 1)) #\t) ; maximizes both cases
                                                          ; takes advantage of the angel, crockblocks the devil
                    ((> (+ *dbag* *margin*) *trust*) #\t) ; crockblock statistical jerks
                    ((< *dbag* *trust*) #\c)              ; reward the trusting (WARN - BACKSTABBING WOULD IMPROVE SCORE)
                    ((and
                        (= (floor *dbag* *margin*) (floor *trust* *margin*))
                        (not (= 0 *dbag* *trust*)))
                        #\t)                              ; try to backstab a purely random opponent, avoid opening w/ a backstab
                    )
        )
        (t #\c)                                            ; defalt case - altruism
    )
)

Le diable

Considérez ce qui suit, format (Player1, Player2)

  • (C, T) - P2 gagne QUATRE POINTS pour sa trahison, tandis que P1 en perd un
  • (T, T) - P2 ET P1 GAIN 1

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.

  • Si vous choisissez le mauvais moment pour vous faire plaisir, vous perdez votre temps.
  • Si vous ratez, au moins vous ne perdez rien.
  • Si vous ratez et qu'il est idiot, vous gagnez 2x plus que si vous aviez été un bon pallier.

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.

GL HF!

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

  1. Ajout d'une variable de marge qui modifie la tolérance de Lisper pour duchebaggery au hasard.
  2. Mise à jour de lisper pour demander aux deux premiers rounds de se mettre du bon pied avec leurs adversaires coopératifs
  3. Utilisation d'un algorithme génétique pour rechercher les valeurs les plus robustes pour le générateur de seuil aléatoire en fonction de leur score cumulatif maximal par rapport à un ensemble standard d'opposants. Mise à jour publiée, y compris.

VERSION OFFICIELLE DE LISPER

Version de développement de LISPER

arrdem
la source
Le score varie selon les variantes du jeu. Je ne joue autour avec des incitations accrues de coopération, et je suis d' accord qu'il aura un effet sur les stratégies choisies. La bonne nouvelle: vous pouvez attraper le marqueur, définir vos propres règles et l’essayer. En principe, vous pouvez même offrir une prime.
dmckee
fink install clisp :: tapoter plusieurs fois ::
dmckee
1
@ josh - merci pour le lien. J'ai lu d'autres pages wikipedia sur ce dilemme, mais j'ai raté cette section. Un bug de règles que je viens de remarquer, il n'y a pas de règles contre les entrées utilisant le système de fichiers. cela crée le potentiel d'une coopération beaucoup plus efficace dans le sens d'une poignée de main.
arrdem
3
There is no reason to EVER (under this scoring system) co-operateest 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.
Peter Taylor
1
N'obtenez-vous pas des erreurs de division par zéro les 3/20 de la dernière version? Chaque fois que (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.
Josh Caswell
5

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 :-)

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
    if (argc == 1)
        printf("t\n");
    else switch (strlen(argv[1])) {
        case 0:
            printf("t\n");
            break;
        case 1:
        case 2:
            printf("c\n");
            break;
        default:
            if (argv[1][0] == 'R' || argv[1][0] == 'E')
                printf("t\n");
            else
                printf("c\n");
            break;
    }

    return 0;
}
Joey
la source
Pas besoin de code dupliqué sur la longueur 1 et 2. Utilisez l' automne par: case 1: case2: printf(...); break;. Et gcc veut une déclaration explicite d’ string.hutiliser strlen. En tout cas je l'ai en cours d'exécution.
dmckee
Ah, c'est vrai. Je ne savais pas comment détecter le tout premier tour, s'il y avait un premier argument vide (historique) ou tout simplement aucun.
Joey
Je ne suis pas sûr. C'est ce que python fait avec Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)quand h = ''. Je devine argc=1.
dmckee
1
Cette séquence initiale est une très bonne idée, visant carrément Tit pour la faiblesse de Tat. Vous obtenez une petite avance, puis vous jouez ensuite.
Josh Caswell
1
@ Josh, où est la petite mine? Contre T4T, cela commence par SRK puis continue avec K. Mais SR rapporte 3 points à chaque joueur.
Peter Taylor
5

Missile anti-T42T

#!/usr/bin/python

"""
Anti-T42T Missile, by Josh Caswell

That Tit-for-two-tats, what a push-over!
  T42T: ccctcctcc...
AT42TM: cttcttctt...
        KSSRSSRSS...
"""
import sys
try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

if history[:2] == 'SS':
    print 'c'
else:
    print 't'

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.

Josh Caswell
la source
J'ai soumis une modification qui fait que celle-ci fonctionne réellement :) Il doit être approuvé.
Casey
@ Casey: bon seigneur, je fais tellement d'erreurs stupides dans mon enthousiasme pour ce problème! Merci, mais pourquoi avez-vous éliminé le sh-bang?
Josh Caswell
Euh, c'était un accident. Je vais le rajouter.
Casey
@ Casey: pas de problème. Je vais le faire. Besoin d'ajouter une chaîne de documentation quand même.
Josh Caswell
4

Convergence

Au départ sympa, puis joue au hasard avec un oeil sur l’histoire de l’adversaire.

/* convergence
 *
 * A iterated prisoners dilemma warrior for
 *
 * Strategy is to randomly chose an action based on the opponent's
 * history, weighting recent rounds most heavily. Important fixed
 * point, we should never be the first to betray.
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char**argv){
  srandom(time(0)+getpid()); /* seed the PRNG */
  unsigned long m=(1LL<<31)-1,q,p=m;
  if (argc>1) {
    size_t i,l=strlen(argv[1]);
    for (i=l; --i<l; ){
      switch (argv[1][i]) {
      case 'R':
      case 'E':
    q = 0;
    break;
      case 'K':
      case 'S':
    q = m/3;
    break;
      }
      p/=3;
      p=2*p+q;
    }
  }
  /* printf("Probability of '%s' is %g.\n",argv[1],(double)p/(double)m); */
  printf("%c\n",(random()>p)?'t':'c'); 
  return 0;
}

J'ai essayé de réduire la pondération de l'historique, mais je ne l'ai pas correctement optimisée.

dmckee
la source
4

Requin

#!/usr/bin/env python

"""
Shark, by Josh Caswell

Carpe stultores.
"""

import sys

HUNGER = 12

try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

if history.count('S') > HUNGER:
    print 't'
else:
    print 'c' if history[0] in "SK" else 't'

Fait assez bien contre la liste de base.

Josh Caswell
la source
... saisir la palourde?
Arrdem
:) Saisir les imbéciles.
Josh Caswell,
+1 pour la tenue d'une 2e place cohérente dans le champ actuel.
arrdem
3

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.

#!/usr/bin/python
import sys

if len(sys.argv) == 1:
    print 'c'
else:
    hist = sys.argv[1]
    if hist[0] == 'K' or hist[0] == 'E':
        print 'c'
    else:
        print 't'
Casey
la source
Cette utilisation ne devrait-elle pas hist[0]( hist[-1]est toujours le premier coup du tour)?
Josh Caswell
Oh wow, tu as raison. J'ai supposé que la chaîne d'entrée avait les tours les plus récents à la fin de la chaîne, pas le début. Fixé.
Casey
3

Honneur parmi les voleurs

#!/usr/bin/env python

"""
Honor Among Thieves, by Josh Caswell

I'd never sell out a fellow thief, but I'll fleece a plump mark,
and I'll cut your throat if you try to cross me.
"""

from __future__ import division
import sys

PLUMPNESS_FACTOR = .33
WARINESS = 10

THIEVES_CANT = "E" + ("K" * WARINESS)

try:
    history = sys.argv[1]
except IndexError:
    history = ""

if history:
    sucker_ratio = (history.count('K') + history.count('S')) / len(history)
    seem_to_have_a_sucker = sucker_ratio > PLUMPNESS_FACTOR


# "Hey, nice t' meetcha."
if len(history) < WARINESS:
    #"Nice day, right?"
    if not set(history).intersection("RE"):
        print 'c'
    # "You sunnuvab..."
    else:
        print 't'

# "Hey, lemme show ya this game. Watch the queen..."
elif len(history) == WARINESS and seem_to_have_a_sucker:
    print 't'

# "Oh, s#!t, McWongski, I swear I din't know dat were you."
elif history[-len(THIEVES_CANT):] == THIEVES_CANT:

    # "Nobody does dat t' me!"
    if set(history[:-len(THIEVES_CANT)]).intersection("RE"):
        print 't'
    # "Hey, McWongski, I got dis job we could do..."
    else:
        print 'c'

# "Do you know who I am?!"
elif set(history).intersection("RE"):
    print 't'

# "Ah, ya almos' had da queen dat time. One more try, free, hey? G'head!"
elif seem_to_have_a_sucker:
    print 't'

# "Boy, you don't say much, do ya?"
else:
    print 'c'

Notez qu’il THIEVES_CANTs’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.

Josh Caswell
la source
+1 pour avoir été le premier strat à tromper de manière fiable le liseur. Marge moyenne de victoire - 300 pts.
arrdem
Semble être le plus fort dans un tourney run du champ actuel.
Peter Taylor
En fait, non, Druid est maintenant que j'ai corrigé le bogue dans le marqueur.
Peter Taylor
@ rmckenzie, @Peter: Décidément, vraiment? J'allais juste pour la personnalité.
Josh Caswell
@josh - plus maintenant .... sur le nouveau code de scoring Le code de scoring de @ casey Lisper est de nouveau sur la première place, suivi de shark.
arrdem
3

"Probabimatic"

Commence par coopérer, puis choisit l'option qui lui donne la valeur attendue la plus élevée. Simple.

#include <stdio.h>

void counts(char* str, int* k, int* r, int* s, int* e) {
    *k = *r = *s = *e = 0;
    char c;
    for (c = *str; c = *str; str++) {
        switch (c) {
            case 'K': (*k)++; break;
            case 'R': (*r)++; break;
            case 'S': (*s)++; break;
            case 'E': (*e)++; break;
        }
    }
}

// Calculates the expected value of cooperating and defecting in this round. If we haven't cooperated/defected yet, a 50% chance of the opponent defecting is assumed.
void expval(int k, int r, int s, int e, float* coop, float* def) {
    if (!k && !r) {
        *coop = .5;
    } else {
        *coop = 2 * (float)k / (k + r) - (float)r / (k + r);
    }
    if (!s && !e) {
        *def = 2.5;
    } else {
        *def = 4 * (float)s / (s + e) + (float)e / (s + e);
    }
}

int main(int argc, char** argv) {
    if (argc == 1) {
        // Always start out nice.
        putchar('c');
    } else {
        int k, r, s, e;
        counts(argv[1], &k, &r, &s, &e);
        float coop, def;
        expval(k, r, s, e, &coop, &def);
        if (coop > def) {
            putchar('c');
        } else {
            // If the expected values are the same, we can do whatever we want.
            putchar('t');
        }
    }
    return 0;
}

Utilisé pour commencer par coopérer, il semble maintenant que la défection fonctionne mieux. EDIT: Oh, attendez, ce n'est pas le cas.

Lowjacker
la source
1
Un autre statisticien! Voyons comment cela joue contre ses collègues calculatrices !
Josh Caswell
En passant, si vous passez for (char c = *str;à char c; for (c = *str;alors gcc compilera ceci sans se plaindre de le mettre en mode C99.
Peter Taylor
3

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.

import java.util.*;

public class HyperrationalWasp
{
    // I'm avoiding enums so as not to clutter up the warriors directory with extra class files.
    private static String Clam = "c";
    private static String Rat = "t";
    private static String Ambiguous = "x";

    private static final String PROLOGUE = "ttc";

    private static int n;
    private static String myActions;
    private static String hisActions;

    private static String decideMove() {
        if (n < PROLOGUE.length()) return PROLOGUE.substring(n, n+1);

        // KISS - rather an easy special case here than a complex one later
        if (mirrorMatch()) return Clam;
        if (n == 99) return Rat; // This is rational rather than superrational

        int memory = estimateMemory();
        if (memory == 0) return Rat; // I don't think the opponent will punish me
        if (memory > 0) {
            Map<String, String> memoryModel = buildMemoryModel(memory);
            String myRecentHistory = myActions.substring(0, memory - 1);
            // I don't think the opponent will punish me.
            if (Clam.equals(memoryModel.get(Rat + myRecentHistory))) return Rat;
            // I think the opponent will defect whatever I do.
            if (Rat.equals(memoryModel.get(Clam + myRecentHistory))) return Rat;
            // Opponent will cooperate unless I defect.
            return Clam;
        }

        // Haven't figured out opponent's strategy. Tit for tat is a reasonable fallback.
        return hisAction(0);
    }

    private static int estimateMemory() {
        if (hisActions.substring(0, n-1).equals(hisActions.substring(1, n))) return 0;

        int memory = -1; // Superrational?
        for (int probe = 1; probe < 5; probe++) {
            Map<String, String> memoryModel = buildMemoryModel(probe);
            if (memoryModel.size() <= 1 || memoryModel.values().contains(Ambiguous)) {
                break;
            }
            memory = probe;
        }

        if (memory == -1 && isOpponentRandom()) return 0;

        return memory;
    }

    private static boolean isOpponentRandom() {
        // We only call this if the opponent appears not have have a small fixed memory,
        // so there's no point trying anything complicated. This is supposed to be a Wilson
        // confidence test, although my stats is so rusty there's a 50/50 chance that I've
        // got the two probabilities (null hypothesis of 0.5 and observed) the wrong way round.
        if (n < 10) return false; // Not enough data.
        double p = count(hisActions, Clam) / (double)n;
        double z = 2;
        double d = 1 + z*z/n;
        double e = p + z*z/(2*n);
        double var = z * Math.sqrt(p*(1-p)/n + z*z/(4*n*n));
        return (e - var) <= 0.5 * d && 0.5 * d <= (e + var);
    }

    private static Map<String, String> buildMemoryModel(int memory) {
        // It's reasonable to have a hard-coded prologue to probe opponent's behaviour,
        // and that shouldn't be taken into account.
        int skip = 0;
        if (n > 10) skip = n / 2;
        if (skip > 12) skip = 12;

        Map<String, String> memoryModel = buildMemoryModel(memory, skip);
        // If we're not getting any useful information after skipping prologue, take it into account.
        if (memoryModel.size() <= 1 && !memoryModel.values().contains(Ambiguous)) {
            memoryModel = buildMemoryModel(memory, 0);
        }
        return memoryModel;
    }

    private static Map<String, String> buildMemoryModel(int memory, int skip) {
        Map<String, String> model = new HashMap<String, String>();
        for (int off = 0; off < n - memory - 1 - skip; off++) {
            String result = hisAction(off);
            String hypotheticalCause = myActions.substring(off+1, off+1+memory);
            String prev = model.put(hypotheticalCause, result);
            if (prev != null && !prev.equals(result)) model.put(hypotheticalCause, Ambiguous);
        }
        return model;
    }

    private static boolean mirrorMatch() { return hisActions.matches("c*ctt"); }
    private static String myAction(int idx) { return myActions.substring(idx, idx+1).intern(); }
    private static String hisAction(int idx) { return hisActions.substring(idx, idx+1).intern(); }
    private static int count(String actions, String action) {
        int count = 0;
        for (int idx = 0; idx < actions.length(); ) {
            int off = actions.indexOf(action, idx);
            if (off < 0) break;
            count++;
            idx = off + 1;
        }
        return count;
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            hisActions = myActions = "";
            n = 0;
        }
        else {
            n = args[0].length();
            myActions = args[0].replaceAll("[KR]", Clam).replaceAll("[SE]", Rat);
            hisActions = args[0].replaceAll("[KS]", Clam).replaceAll("[RE]", Rat);
        }

        System.out.println(decideMove());
    }

}

Les modifications que j'ai apportées au marqueur pour exécuter ceci sont:

17a18
> import re
22a24
> GCC_PATH = 'gcc'                #path to c compiler
24c26
< JAVA_PATH = '/usr/bin/java'   #path to java vm
---
> JAVA_PATH = '/usr/bin/java'     #path to java vm
50,55c52,59
<         elif ext == '.java':
<             if subprocess.call([JAVAC_PATH, self.filename]) == 0:
<                 print 'compiled java: ' + self.filename
<                 classname = re.sub('\.java$', '', self.filename)
<                 classname = re.sub('/', '.', classname);
<                 return JAVA_PATH + " " + classname
---
>         elif ext == '.class':
>             # We assume further down in compilation and here that Java classes are in the default package
>             classname = re.sub('.*[/\\\\]', '', self.filename)
>             dir = self.filename[0:(len(self.filename)-len(classname))]
>             if (len(dir) > 0):
>                 dir = "-cp " + dir + " "
>             classname = re.sub('\\.class$', '', classname);
>             return JAVA_PATH + " " + dir + classname
196c200,201
<         if os.path.isdir(sys.argv[1]):
---
>         warriors_dir = re.sub('/$', '', sys.argv[1])
>         if os.path.isdir(warriors_dir):
198,200c203,211
<             for foo in os.listdir("./src/"): # build all c/c++ champs first.
<                 os.system(str("gcc -o ./warriors/" + os.path.splitext(os.path.split(foo)[1])[0] + " ./src/" + foo ))
<                 #print str("gcc -o ./warriors/" + os.path.splitext(os.path.split(foo)[1])[0] + " ./src/" + foo )
---
>             for foo in os.listdir("./src/"): # build all c/c++/java champs first.
>                 filename = os.path.split(foo)[-1]
>                 base, ext = os.path.splitext(filename)
>                 if (ext == '.c') or (ext == '.cpp'):
>                     subprocess.call(["gcc", "-o", warriors_dir + "/" + base, "./src/" + foo])
>                 elif (ext == '.java'):
>                     subprocess.call([JAVAC_PATH, "-d", warriors_dir, "./src/" + foo])
>                 else:
>                     print "No compiler registered for ", foo
202,203c213,214
<             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)]
---
>             print "Finding warriors in " + warriors_dir
>             players = [warriors_dir+"/"+exe for exe in os.listdir(warriors_dir) if (os.access(warriors_dir+"/"+exe,os.X_OK) or os.path.splitext(exe)[-1] == '.class')]

Merci à @rmckenzie pour avoir intégré ma fonction challenger.

Peter Taylor
la source
Juste une question de style .... le fichier .java doit-il être considéré comme "source" et déplacé vers le répertoire ./src et la dernière .class placée dans le dossier ./warriors par le même indice que celui utilisé dans les fichiers .c, ou est-ce que java est interprété et en tant que tel, les .java et .class restent ensemble? Quoi qu'il en soit, les changements apportés au marqueur vont les avoir dans la statistique du repo.
Arrdem
@rmckenzie, bon point: oui, techniquement, c'est compilé. La raison pour laquelle j'ai eu le fichier source dans le répertoire warriors est que les fichiers python sont là aussi - et ils sont compilés. Si vous le souhaitez, je peux vérifier les modifications nécessaires pour le compiler de ./src à ./warriors - mais cela nécessitera quelques arguments du compilateur, car Java suppose par défaut que la structure de répertoires reflète le package (espace de nom).
Peter Taylor
@peter, je me demandais ... les guerriers se trouvent dans ./warriors en raison de leur * nix 777, ou de quelque autre exécutable. Les scripts Python et Lisp sont NOMINALEMENT compilés pour améliorer les performances, mais sont exécutables dans leur état naturel (source). À MA SAVOIR EN TANT QUE PERSONNE NON JAVA, les fichiers .java ne disposent pas de ces autorisations et ne s'affichent donc pas. C'est pour ça que le hack existe ... parce que la compilation est une étape séparée. Donc voilà. J'apprécierais beaucoup si vous envisagiez de faire ce changement. REPO LINK
arrdem
En utilisant votre code et une guêpe chmod 777'd, la machine virtuelle Java a lancé cette beauté. 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)
arrdem
@ rmckenzie, c'est étrange. En tout cas, je pense que je vais avoir un patch pour vous très bientôt. J'ai dû pirater le code de chargement, car les fichiers de classe ne sont pas exécutables. Et si d'autres entrées Java utilisent des classes internes, cela se cassera.
Peter Taylor
3

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.

#include <stdio.h>
#include <string.h>

int main(int argc, char * argv[]) {
    int d = 0, i, l;

    if (argc == 1) {
        printf("c\n");
    } else {
        l = strlen(argv[1]);

        for (i = 0; i < l; i++)
            if (argv[1][i] == 'R' || argv[1][i] == 'E')
                d++;

        printf("%c\n", d > l/2 ? 't' : 'c');
    }
}
Joey
la source
Votre code est soft_majo, mais votre description est hard_majo.
Peter Taylor
Peter: Eek, désolé; fixé.
Joey
3

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.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define THRESHOLD 7
#define RAND 32

int main(int c, char * a []) {
    int r;
    char * x;
    int d = 0;

    srandom(time(0) + getpid());

    if (c == 1) {
        printf("c\n");
        return 0;
    }

    for (x = a[1]; *x; x++)
        if (*x == 'R' || *x == 'E') d++;

    if (d > THRESHOLD || random() % 1024 < RAND || strlen(a[1]) == 99)
        printf("t\n");
    else
        printf("c\n");

    return 0;
}
Joey
la source
Contre HyperrationalWasp, il agira généralement plus ou moins contre le diable. Il commence simplement par coopérer tout le temps, donc je suppose que c'est l'ange et je passe à l'attaque. Ensuite, quand le seuil sera atteint, vous passerez en mode diable et je passerai en t4t. Si elle frappe au hasard dans les 6 premiers coups, je passerai au t4t avant de passer au diable, mais les chances de le faire ne sont pas élevées.
Peter Taylor
1
Peter: Eh bien, je teste rarement les stratégies directement les unes contre les autres, car le domaine dans son ensemble a une certaine influence sur la performance de la stratégie. Actuellement, il se bat principalement avec progressive et druide pour la première place dans mes tests.
Joey
Graduel et druide marquent chacun environ 200 points contre Wasp; ventouse aléatoire marquera environ 83.
Peter Taylor
2

BYGONES

#!/usr/bin/env python

"""
BYGONES, entry to 1P5 Iterated Prisoner's Dilemma, by Josh Caswell

Cooperates at first, plays as Tit for Tat for `bygones * 2` rounds, then checks 
history: if there's too much ratting, get mad and defect; too much 
suckering, feel bad and cooperate.
"""

bygones = 5

import sys

# React to strangers with trust.
try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

replies = { 'K' : 'c', 'S' : 'c',
            'R' : 't', 'E' : 't' }

# Reply in kind.
if len(history) < bygones * 2:
    print replies[history[0]]
    sys.exit(0)

# Reflect on past interactions.
faithful_count = history.count('K')
sucker_count = history.count('S')
rat_count = history.count('R')

# Reprisal. 
if rat_count > faithful_count + bygones:
    # Screw you!
    print 't'
    sys.exit(0)

# Reparation.
if sucker_count > faithful_count + bygones:
    # Geez, I've really been mean.
    print 'c'
    sys.exit(0)

# Resolve to be more forgiving.
two_tats = ("RR", "RE", "ER", "EE")
print 't' if history[:2] in two_tats else 'c'

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.

Josh Caswell
la source
2

Aide Vampire

#!/usr/bin/env python

"""
Help Vampire, entry to 1P5 Iterated Prisoner's Dilemma,
by Josh Caswell.

1. Appear Cooperative 2. Acknowledge Chastisement 
3. Act contritely 4. Abuse charity 5. Continual affliction
"""

import sys
from os import urandom

LEN_ABASHMENT = 5

try:
    history = sys.argv[1]
except IndexError:
    print 'c'    # Appear cooperative
    sys.exit(0)

# Acknowledge chastisement
if history[0] in "RE":
    print 'c'
# Act contritely
elif set(history[:LEN_ABASHMENT]).intersection(set("RE")):
    print 'c'
# Abuse charity
elif history[0] == 'S':
    print 't'
# Continual affliction
else:
    print 't' if ord(urandom(1)) % 3 else 'c'

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.

Josh Caswell
la source
2

Druide

#!/usr/bin/env python

"""
Druid, by Josh Caswell

Druids are slow to anger, but do not forget.
"""

import sys
from itertools import groupby

FORBEARANCE = 7
TOLERANCE = FORBEARANCE + 5

try:
    history = sys.argv[1]
except IndexError:
    history = ""

# If there's been too much defection overall, defect
if (history.count('E') > TOLERANCE) or (history.count('R') > TOLERANCE):
    print 't'
# Too much consecutively, defect
elif max([0] + [len(list(g)) for k,g in     # The 0 prevents dying on []
                groupby(history) if k in 'ER']) > FORBEARANCE:
    print 't'
# Otherwise, be nice
else:
    print 'c'

Fait raisonnablement bien contre la liste de base.

Josh Caswell
la source
2

Niais

#!/usr/bin/env python

"""
Simpleton, by Josh Caswell

Quick to anger, quick to forget, unable to take advantage of opportunity.
"""

import sys
from os import urandom

WHIMSY = 17

try:
    history = sys.argv[1]
except IndexError:
    if not ord(urandom(1)) % WHIMSY:
        print 't'
    else:
        print 'c'
    sys.exit(0)

if history[0] in "RE":
    print 't'
elif not ord(urandom(1)) % WHIMSY:
    print 't'
else:
    print 'c'

Est-ce que ça va contre l'alignement de la base?

Josh Caswell
la source
2

Petit Schemer

#!/usr/bin/env python

"""
The Little Schemer, by Josh Caswell

No relation to the book. Keeps opponent's trust > suspicion 
by at least 10%, trying to ride the line.
"""

from __future__ import division
import sys
from os import urandom

out = sys.stderr.write

def randrange(n):
    if n == 0:
        return 0
    else:
        return ord(urandom(1)) % n

try:
    history = sys.argv[1]
except IndexError:
    print 'c'
    sys.exit(0)

R_count = history.count('R')
S_count = history.count('S')
K_count = history.count('K')
E_count = history.count('E')

# Suspicion is _S_ and E because it's _opponent's_ suspicion
suspicion = (S_count + E_count) / len(history)
# Likewise trust
trust = (K_count + R_count) / len(history)

if suspicion > trust:
    print 'c'
else:
    projected_suspicion = (1 + S_count + E_count) / (len(history) + 1)
    projected_trust = (1 + K_count + R_count) / (len(history) + 1)

    leeway = projected_trust - projected_suspicion
    odds = int(divmod(leeway, 0.1)[0])

    print 't' if randrange(odds) else 'c'

Fait mal contre la base, mais assez bien contre la cible. De toute évidence, pas écrit dans Scheme.

Josh Caswell
la source
Pourquoi est-ce que je sens un défi?
arrdem
Vaincu ce bougre .... randomisé le seuil dans Lisper.
arrdem
@ rmckenzie: mais en quoi cela a-t-il affecté votre jeu contre le reste du terrain? Avec suffisamment de collaborateurs travaillant les uns avec les autres, les stratégies paranoïaques ou envieuses vont commencer à faire pire. Vous avez également une limite supérieure fixe, qui pourrait être exploitée.
Josh Caswell
Si vous lisez le liseuse actuel, c'est plus défensif que jaloux. Il essaie de détecter les opposants qui poursuivent des strats statistiquement traîtres de la sorte, et ne rentre alors que le feu. Son ouverture CC est conçue pour démarrer du bon pied avec Thieves et présente l’avantage supplémentaire de convaincre la plupart des membres de la coopérative de jouer.
Arrdem
@ rmckenzie: très bien! Je vais essayer.
Josh Caswell,
1

Tit pour deux tatouages

un autre vieux favori

#!/usr/bin/env python

"""
Tit For Two Tats, entry to 1P5 Iterated Prisoner's Dilemma, 
    by Josh Caswell (not an original idea).

Cooperates unless opponent has defected in the last two rounds.
"""

import sys
try:
    history = sys.argv[1]
except IndexError:
    history = ""

two_tats = ("RR", "RE", "ER", "EE")

if len(history) < 2:
    print 'c'
else:
    print 't' if history[:2] in two_tats else 'c'
Josh Caswell
la source
Vous ne pouvez faire un retour que si vous êtes dans une fonction. Peut-être utiliser 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 une IndexErrorperte de temps argv[1].
Casey
Vous avez peut-être laissé de côté l' len(history)<2article, car ce dernier ressemble à la elsepartie.
dmckee
@ Casey @dmckee Merci pour les corrections de bugs. "Duh" sur moi returnsurtout!
Josh Caswell
@dmckee: Cela a commencé dans le cadre d'une chose plus compliquée, puis je me suis rendu compte que j'avais réécrit Tit pour Two Tats et que j'avais décidé d'y participer. Copier-coller erreur d'utilisateur.
Josh Caswell
@Josh: J'ai vu votre entrée Bygones brièvement, l'avez-vous supprimée? Cela semblait intéressé.
Casey