1P5: Dilemma del prigioniero iterato


35

Questo compito fa parte del primo periodico Premier Programming Puzzle Push ed è inteso come dimostrazione della nuova proposta di sfida tipo .

Il compito è scrivere un programma per interpretare il dilemma del prigioniero ripetuto meglio degli altri partecipanti.

Guarda, Vinny. Conosciamo il tuo compagno di cella --- come si chiama? Sì, McWongski, il mafioso nippo-irlandese-ucraino - sta a qualcosa e tu sai di cosa si tratta.

Stiamo cercando di essere gentili qui, Vinnie. Ti sto dando una possibilità.

Se ci dici cosa sta pianificando, ti vedremo ottenere un buon incarico di lavoro.

E se non lo fai ...

Le regole del gioco

  • Il concorso consiste in un round robin completo (tutti i possibili accoppiamenti) di due concorrenti alla volta (inclusi i giochi di auto).
  • Ci sono 100 round giocati tra ogni coppia
  • Ad ogni round viene chiesto a ciascun giocatore di scegliere tra cooperare con l'altro giocatore o tradirlo, senza conoscere le intenzioni degli altri giocatori in materia, ma con un ricordo dei risultati dei round precedenti giocati contro questo avversario.
  • I punti vengono assegnati per ogni round in base alla scelta combinata. Se entrambi i giocatori cooperano ottengono 2 punti ciascuno. Il tradimento reciproco produce 1 punto ciascuno. Nel caso misto, al giocatore traditore vengono assegnati 4 punti e il collaboratore viene penalizzato di 1.
  • Una partita "ufficiale" si svolgerà non prima di 10 giorni dopo la pubblicazione con tutti gli invii che posso mettere al lavoro e sarà utilizzato per selezionare il vincitore "accettato". Ho una confezione di Mac OS 10.5, quindi le soluzioni POSIX dovrebbero funzionare, ma ci sono dei linuxismi che non lo fanno. Allo stesso modo, non ho supporto per l'API win32. Sono disposto a fare uno sforzo di base per installare le cose, ma c'è un limite. I limiti del mio sistema non rappresentano in alcun modo i limiti delle risposte accettabili, semplicemente quelli che saranno inclusi nella corrispondenza "ufficiale".

L'interfaccia del programmatore

  • Le voci devono essere sotto forma di programmi che possono essere eseguiti dalla riga di comando; la decisione deve l'output (unico!) del programma sull'output standard. La storia dei round precedenti con questo avversario verrà presentata come argomento da riga di comando.
  • L'output è "c" (per clam up ) o "t" (per tell all ).
  • La cronologia è una singola serie di caratteri che rappresentano i round precedenti con i round più recenti che arrivano prima nella stringa. I personaggi sono
    • "K" (per mantenere la fede che significa cooperazione reciproca)
    • "R" (per rat b @ st @ rd mi ha esaurito! )
    • "S" (per ventosa! Nel senso che hai beneficiato di un tradimento)
    • "E" (per tutti è alla ricerca del numero uno sul tradimento reciproco)

La staffa

Quattro giocatori saranno forniti dall'autore

  • Angelo - collabora sempre
  • Diavolo: parla sempre
  • TitForTat - Collabora al primo round, quindi fa sempre quello che aveva fatto nell'ultimo round
  • Casuale - 50/50

a cui aggiungerò tutte le voci che posso eseguire.

Il punteggio totale sarà il punteggio totale contro tutti gli avversari (inclusi i self-play una sola volta e usando il punteggio medio).

I partecipanti

(attuale dal 2 maggio 2011 alle 7:00)

La stretta di mano segreta | Missile anti-T42T | Diffidenza (variante) | Stretta di mano | The Little Lisper | Convergenza | Squalo | Probabimatico | Pavlov - Win Stay, Lose Switch | Honor Among Thieves | Aiuta il vampiro | Druido | Piccolo Schemer | Passate | Tit for Two Tats | Simpleton |

marcatore

#! /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
  • I reclami sul mio orribile pitone sono i benvenuti, poiché sono sicuro che questo fa schifo in più di un modo
  • Correzioni di bug benvenute

Log dei marcatori:

  • Stampa i giocatori e i punteggi ordinati e dichiara un vincitore (4/29, Casey)
  • Opzionalmente esegui più tornei ( ./score warriors/ num_tournaments)) default = 1, rileva e compila sorgenti python (4/29, Casey)
  • Risolto un bug particolarmente stupido in cui al secondo giocatore veniva passata una cronologia errata. (4/30, dmckee; grazie Josh)

Guerrieri iniziali

A titolo esemplificativo e affinché i risultati possano essere verificati

Angelo

#include <stdio.h>
int main(int argc, char**argv){
  printf("c\n");
  return 0;
}

o

#!/bin/sh
echo c

o

#!/usr/bin/python
print 'c'

diavolo

#include <stdio.h>
int main(int argc, char**argv){
  printf("t\n");
  return 0;
}

Casuale

#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;
}

Nota che il segnapunti può richiamare più volte il guerriero in un secondo, quindi è necessario compiere uno sforzo serio per assicurare la casualità dei risultati se si utilizza il tempo per seminare il 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;
}

Il primo che in realtà fa qualcosa con la storia.

Eseguendo il segnapunti solo sui guerrieri forniti si ottiene

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)

Quel diavolo, è un mestiere, e apparentemente i bravi ragazzi entrano per ultimi.

risultati

della corsa "ufficiale"

('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

2
Se il mio compagno di cella è Nippo-Irlandese-Ucraino, perché il suo nome sembra Hiberno-Cino-Russo?
Peter Taylor,

2
@Peter: LOL. La verità? Bene, (1) le genealogie non sono chiare, ma probabilmente vengo dal mio micio attraverso lo scozzese-irlandese; (2) dopo aver scritto "Nippo" ho provato varie parti dei nomi dei miei amici dalla terra del sol levante e non mi è piaciuto il modo in cui hanno scannerizzato, quindi sono andato avanti e ho usato un cognome cinese che suonava bene invece, e (3) non saprei la differenza se a turno mi picchiassero con i ferri delle gomme. Il che sembra probabile in base alle circostanze.
dmckee,

1
@Josh: Sarebbe semplice passare return (s1, L1+h1), (s2, L2+h1)a return (s1, L1+h1), (s2, L2+h2)[Nota L2+h2anziché L2+h1alla fine]? // Errore Cut-n-paste o qualcosa di altrettanto idiota. Sheesh!
dmckee,

2
Ho trascorso del tempo sullo script di test e sono lieto di annunciare un aggiornamento qui . Questo aggiornamento aggiunge una semplice shell allo script di test, che consente all'utente di eseguire manualmente questo bot rispetto a quel bot, eseguire tornei con campi riservati e altre cose interessanti. Sentiti libero di dare suggerimenti! Oh. E devo a @josh l'idea del bot-vs-bot. È davvero solo un'implementazione più elaborata della sua sceneggiatura da "trainer".
arrdem,

2
Interessante: c'erano 23 concorrenti, quindi ognuno ha giocato 22 round. Se tutti avessero giocato a "Angel" ogni punteggio sarebbe stato di 4400, ma anche il miglior punteggio di 4167 non corrispondeva a quello. Se solo
vivessimo

Risposte:


11

Graduale

Questa strategia si basa su un articolo di Beaufils, Delahaye e Mathieu . La mia C non è davvero la migliore, quindi se qualcuno ha qualche suggerimento per migliorare / accelerare il codice, fammi sapere!

[Modifica] Vale la pena notare che Gradual è stato progettato per essere una strategia che supera Tit per Tat. Ha proprietà simili in quanto è disposto a cooperare e reagire contro un avversario difettoso. A differenza di Tit for Tat, che ha solo un ricordo dell'ultimo round giocato, Gradual ricorderà la completa interazione e difetterà il numero di volte che l'avversario ha disertato finora. Tuttavia, offrirà nuovamente una cooperazione reciproca.

Come al solito, la performance della strategia dipende un po 'dall'allineamento di altre strategie. Anche il documento originale non era molto chiaro su alcuni dettagli.

#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;
}

11

La stretta di mano segreta

#!/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 strategia qui è di sacrificare i primi 10 round per eseguire una stretta di mano "segreta". Se sono pieno di me stesso, allora riconosco la storia delle prime 10 mosse e metto il mio cappello da angelo per il resto del gioco. Non appena riconosco che il mio compagno di cella non è me stesso, mi trasformo in un diavolo nel tentativo di sfruttare i compagni di cella troppo cooperativi.

Se sacrificare i primi 10 round mi permetterà di eliminare il Diavolo stesso dipende fortemente da quante voci ci sono. Per ridurre al minimo il danno, solo 3 cooperativi si presentano nella stretta di mano.

Modifica: TAGMATCH dinamico ora per prevenire errori stupidi come cambiarne solo uno e così posso rendere TAG dinamico ad un certo punto in futuro.

Modifica 2: ora genera in modo casuale il tag alla prima esecuzione e lo memorizza nel file specificato da sys.argv[0]( .pycsostituito da in .pymodo che vada al codice, non per codice, file). Penso che questa sia l'unica informazione che tutti i miei casi hanno che nessun altro ha, quindi sembra l'unica opzione per evitare i parassiti.


Ma come fa il tuo doppelganger a farsi un diavolo?
arrdem,

1
(Mi sento come un pappagallo, dicendo "Tit for Tat" tutto il tempo ...) Nota che T4T batterà la tua strategia in un abbinamento contro: T4T (collabora in precedenza) e Devil (meno risultati di ratti), e si legherà con il tuo strategia. Naturalmente, il totale generale, non il totale di accoppiamento, è ciò che conta alla fine. Come dici tu, la popolazione è importante.
Josh Caswell

1
Oh, no, ottieni una S in più da Tit per Tat. Bello. Non mi rendevo conto che TAGveniva riprodotto al contrario . Tuttavia, non dovresti TAGMATCHessere 'KEEEKEEEKE'? "".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
Josh Caswell,

@John. Bene: inizialmente avevo un TAG diverso e quando l'ho modificato per ridurre al minimo la cooperazione, ho dimenticato di aggiornare TAGMATCH. @Arrdem L'idea è che se sto giocando contro me stesso, la cosa migliore da fare è che entrambi cooperino continuamente per massimizzare la somma dei loro punteggi.
Aaron Dufour,

1
Aww, accidenti. Quindi ora devo cercare tutti i .pyfile per il tuo codice ed estrarre il TAG. Non lo farò in C, però ...
Joey,

6

The Little 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
    )
)

Il diavolo

Considera il formato seguente (Player1, Player2)

  • (C, T) - P2 guadagna QUATTRO PUNTI per il suo tradimento, mentre P1 LOOSES ONE
  • (T, T) - P2 E P1 GAIN 1

Supponendo che P2 sia il diavolo, non c'è modo in cui il diavolo possa mai perdere punti, in realtà il peggio che può fare è guadagnare solo un punto. Quindi, contro un avversario puramente casuale, il peggior punteggio possibile del diavolo sarà esattamente (5/2) * n dove n è il numero di "partite" giocate. Il suo caso peggiore assoluto è contro se stesso, dove il suo punteggio sarà n, e il suo caso migliore è contro un angelo, che sarà 4 * n

Asserire: optim_strat = diavolo

questo è un torneo. Il pugnalato alle spalle del mio compagno di cella è una strategia molto migliore della cooperazione perché aiuta di più il MIO PUNTEGGIO (+4). BONUS - viene sbattuto (-1)! Se gli tiro fuori il collo, rimango per guadagnare (+2) e perdere (-1). Per questo, statisticamente, i pugnalati alle spalle sono premiati.

Ma è ottimale?

Non c'è motivo di collaborare MAI (con questo sistema di punteggio).

  • Se hai scelto il momento sbagliato per mollare, perdi.
  • Se tocchi, almeno non perdi nulla.
  • Se fai il ratto ed è stupido, guadagni il doppio in più rispetto a se fossi stato un bravo pall.

Nel sistema KOTH, la massimizzazione dei rendimenti è essenziale. Anche se hai due robot perfettamente sincronizzati e cooperanti, i loro punteggi individuali verranno comunque potenziati di 200 punti per la loro sportività. D'altra parte, un diavolo guadagnerà almeno 100 punti, con un caso medio di 200 e un massimo di 400, e costerà ai suoi avversari fino a 100 punti ciascuno! Quindi praticamente, il diavolo segna davvero una partita media di 300, arrivando a 500.

In conclusione: il tempo lo dirà

Per me, sembra che il punteggio debba essere preso in considerazione per paura che il diavolo prenda la giornata. Aumentare il punteggio di cooperazione a 3 tutto potrebbe farlo. È tuttavia possibile rilevare i diavoli e impedire loro di segnare i loro 400, come mostrano pavlov e dispetto. Posso dimostrare che uno dei due raccoglierà abbastanza punti per la sua cooperazione da giustificare la propria fede? no. Tutto ciò dipende dal campo finale dei contendenti.

GL, HF!

E per favore, fai del tuo peggio per questo post. Voglio scrivere il mio documento senior su questo quando tutto è stato detto e fatto.

Cronologia delle versioni

  1. Aggiunta una variabile di margine che modifica casualmente la tolleranza di Lisper per i bagagli.
  2. Aggiornato lisper a clam per i primi due round per scendere con il piede destro con gli avversari cooperativi
  3. Utilizzato un algoritmo genetico per trovare i valori più robusti per il generatore di soglia casuale in base al loro punteggio cumulativo massimo rispetto a un set standard di avversari. Aggiornamento pubblicato incluso loro.

VERSIONE UFFICIALE DI LISPER

SVILUPPARE LA VERSIONE DI LISPER


Il punteggio varia in diverse varianti del gioco. Ho fatto giocare con l'aumentare l'incentivo della cooperazione, e sono d'accordo che avrà un effetto sulle strategie scelte. La buona notizia: si può afferrare il miglior marcatore, impostare le proprie regole e provarlo. In linea di principio potresti anche offrire una taglia.
dmckee,

fink install clisp :: toccando ripetutamente le dita ::
dmckee

1
@josh - grazie per il link. Ho letto alcune altre pagine di Wikipedia su questo dilemma, ma mi mancava quella sezione. Un bug delle regole che ho appena notato, non ci sono regole contro le voci che usano il filesystem. questo crea il potenziale per una cooperazione molto più efficiente lungo le linee della stretta di mano.
arrdem,

3
There is no reason to EVER (under this scoring system) co-operateè solo mezzo corretto. Se sai che il tuo avversario non tiene conto della storia (angelo, diavolo, casuale), dovresti sempre difettare. Se il tuo avversario tiene conto della cronologia e puoi sincronizzare, allora puoi fare di meglio. Ho un paio di idee che ruotano attorno al rilevare se l'avversario è razionale o superrazionale.
Peter Taylor,

1
Non stai ottenendo errori di divisione per zero 3 / 20s del tempo con l'ultima versione? Ogni volta che (random 20)dà 2, 5 o 8, (/ (+1 rand-num) 10)è 0,3, 0,6, 0,9 e il resto della divisione con 0,3 è 0; così (floor *dbag* *margin*)muore.
Josh Caswell

5

Diffidenza (variante)

Questo è uscito prima nei miei test anni fa (all'epoca ero in terza media e ho fatto una piccola tesi su questo esattamente, usando anche strategie ideate da altri studenti). Inizia con la sequenza tcc(e suona come Tit per Tat dopo quello.

Scuse per il codice orribile; se qualcuno può accorciarlo senza giocare a golf, sarei grato :-)

#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;
}

Non c'è bisogno di codice duplicato della lunghezza 1 e 2. Uso caduta attraverso: case 1: case2: printf(...); break;. E gcc vuole una dichiarazione esplicita string.hda usare strlen. In ogni caso ce l'ho in esecuzione.
dmckee,

Ah, è vero. Non ero sicuro di come rilevare il primo round, comunque, se c'è un primo argomento vuoto (storia) o semplicemente nessuno.
Joey,

Non ne sono sicuro. È qualunque cosa faccia Python con Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)quando h = ''. Sto indovinando argc=1.
dmckee,

1
Quella sequenza iniziale è una buona idea, mirando esattamente a Tit per la debolezza di Tat. Ottieni un piccolo vantaggio su di esso, quindi gioca in seguito.
Josh Caswell,

1
@Josh, dov'è il piccolo vantaggio? Contro T4T questo inizia con SRK e poi continua con K. Ma SR vale 3 punti per ogni giocatore.
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'

Fa abbastanza bene contro l'insieme base di guerrieri: uccide Angel, leggermente battuto dal diavolo (ma mantiene basso il suo punteggio), generalmente batte RAND con facilità, e batte appena Tit per Tat. Fa male quando gioca contro se stesso.


Ho inviato una modifica che rende questo effettivamente funzionante :) Deve essere approvato.
Casey,

@Casey: buon dio, sto facendo così tanti stupidi errori nel mio entusiasmo per questo problema! Grazie, ma perché hai eliminato lo sh-bang?
Josh Caswell,

Ehm, quello è stato un incidente. Lo aggiungerò di nuovo.
Casey,

@Casey: nessun problema. Lo farò. È necessario aggiungere comunque una stringa di documenti.
Josh Caswell,

4

Convergenza

Inizialmente bello, quindi gioca in modo casuale con un occhio sulla storia dell'avversario.

/* 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;
}

Ho provato a modificare la ponderazione della storia, ma non l'ho ottimizzata correttamente.


4

Squalo

#!/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'

Fa abbastanza bene contro il registro di base.


... cogliere la vongola?
arrdem,

:) Cogli gli sciocchi.
Josh Caswell

+1 per mantenere un 2 ° posto consistente nel campo corrente.
arrdem,

3

Pavlov: vinci, perdi interruttore

Al primo turno collabora, quindi collabora se e solo se entrambi i giocatori hanno optato per la stessa scelta nella mossa precedente.

#!/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'

Non dovrebbe usare questo hist[0]( hist[-1]è sempre la prima mossa del round)?
Josh Caswell,

Oh wow, hai ragione. Supponevo che la stringa di input avesse i round più recenti alla fine della stringa, non l'inizio. Fisso.
Casey,

3

Honor Among Thieves

#!/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'

Nota che si THIEVES_CANTtratta essenzialmente di una stretta di mano, anche se emergerà solo giocando contro un cooperatore. Tuttavia, evita il problema del parassita controllando le croci successive. Fa abbastanza bene contro il registro di base.


+1 per essere stato il primo strat a trionfare in modo affidabile. Margine di vittoria medio - 300 punti.
arrdem,

Sembra essere il più forte in una corsa di torneo del campo attuale.
Peter Taylor,

In realtà no, Druid è ora che ho corretto il bug nel segnapunti.
Peter Taylor,

@rmckenzie, @Peter: Accidenti, davvero? Stavo solo cercando personalità.
Josh Caswell

@josh - non più .... sul nuovo codice di punteggio @ Codice di punteggio di Casey Lisper è tornato in cima seguito da uno squalo.
arrdem,

3

"Probabimatic"

Inizia collaborando, quindi seleziona l'opzione che offre il valore più alto previsto. Semplice.

#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;
}

Utilizzato per iniziare collaborando, ma ora sembra che i difetti funzionino davvero meglio. EDIT: Oh aspetta, in realtà non lo fa.


1
Un altro statistico! Vediamo come funziona contro i suoi colleghi calcolatori !
Josh Caswell,

A proposito, se cambi for (char c = *str;a char c; for (c = *str;allora gcc lo compilerà senza lamentarti che deve essere messo in modalità C99.
Peter Taylor,

3

Vespa iperrazionale

Implementato in Java perché non ero sicuro della complessità delle strutture dati. Se questo è un problema per qualcuno, penso che posso portarlo a bash senza troppi problemi perché alla fine usa solo semplici array associativi.

Nota : l'ho rimosso da un pacchetto in linea con l'ultima versione della mia patch per il marcatore per gestire Java. Se vuoi pubblicare una soluzione Java che utilizza classi interne, allora dovrai patchare la patch.

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());
    }

}

Le modifiche che ho apportato al marcatore per eseguire questo sono:

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')]

Grazie a @rmckenzie per aver chiuso la mia funzione sfidante.


Solo una questione di stile .... il file .java deve essere considerato "sorgente" e spostato nella directory ./src e nella classe .class finale collocata nella cartella ./warriors dallo stesso pedice utilizzato sui file .c, oppure java viene interpretato e come tale .java e .class stanno insieme? Belle modifiche al segnapunti in ogni caso ... le avranno nel repository stat.
arrdem,

@rmckenzie, buon punto: sì, tecnicamente è compilato. Il motivo per cui avevo il file sorgente nella directory dei guerrieri è che anche i file Python sono lì - e sono compilati. Se vuoi posso controllare quali modifiche sono necessarie per compilarlo da ./src a ./warriors - ma richiederà alcuni argomenti del compilatore, perché Java per impostazione predefinita presuppone che la struttura delle directory rifletta il pacchetto (spazio dei nomi).
Peter Taylor,

@peter, mi stavo solo chiedendo ... i guerrieri si trovano in ./warriors in virtù dell'essere * nix 777, o altrimenti eseguibile. Gli script Python e Lisp sono NOMINALMENTE compilati per le prestazioni, ma sono eseguibili nel loro stato (sorgente) naturale. CON LA MIA CONOSCENZA COME PERSONA NON JAVA, i file .java non dispongono di tali autorizzazioni e quindi non verranno visualizzati. Questo è ciò per cui esiste l'hack c ... perché la compilazione è un passaggio separato. Quindi si Ti sarei molto grato se volessi fare questo cambiamento. REPO LINK
arrdem,

Usando il tuo codice e una vespa chmod 777, la JVM ha lanciato questa bellezza. 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, è strano. Comunque, penso che avrò una patch per te molto presto. Ho dovuto hackerare il codice di caricamento, perché i file di classe non sono eseguibili. E se qualsiasi altra voce Java utilizza classi interne, si romperà.
Peter Taylor,

3

Soft_majo

Ah bene, un'altra delle strategie standard, solo per completare la formazione.

Questo prende la mossa che l'avversario ha fatto di più; se uguale coopera.

#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');
    }
}

Il tuo codice è soft_majo, ma la tua descrizione è hard_majo.
Peter Taylor,

Peter: Eek, scusa; fisso.
Joey,

3

Ventosa casuale

Questo difetterà se l'avversario difetterà troppo spesso (soglia), ma proverà casualmente a pugnalare di volta in volta.

Fa abbastanza bene contro tutti tranne i giocatori Java e Lisp (che non riesco a eseguire, a causa di Java o Lisp sulla macchina di prova); il più delle volte almeno.

#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;
}

Contro HyperrationalWasp generalmente farà all'incirca contro il diavolo. Inizia solo collaborando tutto il tempo, quindi presumo sia l'angelo e vado all'attacco. Quindi quando raggiunge la soglia, passerai alla modalità diavolo e passerò alla t4t. Se nelle prime 6 mosse casualmente torna indietro, allora passerò a t4t prima di passare al diavolo, ma le probabilità di ciò non sono alte.
Peter Taylor,

1
Peter: Beh, raramente metto alla prova le strategie l'una contro l'altra, poiché il campo complessivo ha una certa influenza sulle prestazioni della strategia. Attualmente combatte principalmente con graduale e druido per il primo posto nei miei test.
Joey,

Sia il graduale che il druido segnano circa 200 contro Wasp; ventosa casuale segnerà circa 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'

Non ho ancora trovato il miglior rapporto qualità-prezzo bygones. Non mi aspetto che questa sia una strategia vincente , ma sono interessato all'esecuzione di una strategia qualcosa di simile a ciò che penso sia "buono" nella vita reale. Una revisione futura potrebbe includere anche la verifica del numero di disfunzioni reciproche.


2

Aiuta il vampiro

#!/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'

Ha un risultato asimmetrico in modo divertente se messo contro se stesso. Se solo questa soluzione potesse essere applicata nella vita reale.


2

druido

#!/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'

Fa abbastanza bene contro il registro di base.


2

Sempliciotto

#!/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'

Va bene contro il registro di base.


2

Piccolo 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'

Fa male contro il set di base, ma abbastanza bene contro il suo obiettivo. Ovviamente, non scritto in Scheme.


Perché percepisco una sfida?
arrdem,

Sconfitto questo coglione .... randomizzato la soglia in Lisper.
arrdem,

@rmckenzie: ma come ha influito il tuo gioco sul resto del campo? Con abbastanza collaboratori che collaborano tra loro, le strategie paranoiche o invidiose inizieranno a peggiorare. Hai ancora un limite superiore fisso, che potrebbe essere sfruttato.
Josh Caswell

Se leggi il lisper attuale, è più difensivo che invidioso. Cerca di individuare gli avversari che inseguono stratificazioni statisticamente insidiose come questa, e solo allora restituisce il fuoco. L'apertura CC è progettata per scendere con il piede giusto con i ladri e ha l'ulteriore vantaggio di convincere la maggior parte degli strati cooperativi a giocare insieme.
arrdem,

@rmckenzie: Molto bene! Ci proverò.
Josh Caswell,

1

Tit per due tatuaggi

un altro vecchio preferito

#!/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'

Non puoi effettuare un reso se non sei all'interno di una funzione. Forse usare sys.exit(0)? O lascialo finire. Modifica: anche la prima invocazione al tuo programma è senza cronologia che causa un IndexErrorquando lo fai argv[1].
Casey,

Potresti aver lasciato fuori la len(history)<2clausola, perché l'ultima sembra la elseparte.
dmckee,

@Casey @dmckee Grazie per le correzioni di bug. "Duh" per me in returnparticolare!
Josh Caswell,

@dmckee: questo è iniziato come parte di una cosa più complicata, e poi mi sono reso conto di aver riscritto Tit for Two Tats e ho deciso di inserirlo. Errore utente copia-incolla.
Josh Caswell,

@Josh: ho visto brevemente la tua voce Bygones, l'hai cancellata? Sembrava interessato.
Casey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.