In questa domanda , è stato ideato un gioco in cui i giocatori si affronterebbero a coppie in coppia nel Dilemma del Prigioniero, per determinare quale strategia iterativa ha segnato il punteggio più alto contro gli altri.
In questa domanda , ho escogitato un modo per più persone di giocare il dilemma dei prigionieri l'una contro l'altra allo stesso tempo. In questa variante, la matrice di payoff non è necessaria, con ogni risultato tra ogni coppia di due giocatori che è la somma di due decisioni funzionalmente indipendenti.
Il tuo compito è costruire un'intelligenza artificiale per giocare a questa versione simmetrica e generalizzata del dilemma del prigioniero multiplayer che raggiungerà il punteggio più alto possibile.
Le regole del gioco
In ogni round di questo multiplayer, il multi-round Dilemma del prigioniero, un giocatore A
può decidere di "prendere 1" da un altro giocatore B
. In questa circostanza, A
il punteggio aumenta di 1, mentre B
il punteggio diminuisce di 2. Questa decisione può avvenire tra ogni coppia di giocatori ordinata.
Questa è l'unica decisione presa per ogni giocatore - o "prendere 1" o non "prendere 1" da ogni altro giocatore, che sono omologhi rispettivamente alla defezione e alla cooperazione. La matrice di payoff effettiva tra due giocatori P1
e si P2
presenta come segue:
P1/P2 P1 Take1 P1 Don't
P2 Take1 -1/-1 -2/+1
P2 Don't +1/-2 0/ 0
Procedura del torneo
Il gioco consisterà in P * 25
round, dove P
è il numero di giocatori partecipanti. Tutti i giocatori iniziano con un punteggio di 0
. Ogni round consisterà nella seguente procedura:
All'inizio di un round, a ciascun programma verrà fornita una cronologia dei round precedenti dall'input standard , nel seguente formato:
Una linea che contiene 3 numeri,
P
,D
, eN
.P
è il numero totale di giocatori nel gioco. Ad ogni giocatore viene assegnato in modo casuale un numero ID da1
aP
all'inizio del gioco.D
è l'ID del giocatore corrente.N
è il numero di round giocati.
N
linee, ciascuna linea che rappresenta i risultati di un round. Sulla lineak
diN
, ci sarà un certo numeron_k
di coppie ordinate(a, b)
, separate da spazi, che indicano che il giocatore con IDa
"ha preso 1" dal giocatore con IDb
in quel round.Un numero uniformemente casuale
R
da0
a18446744073709551615
(2 64 - 1), per agire come seme pseudocasuale. Questi numeri verranno letti da un file pre-generato, che verrà rilasciato alla fine del torneo in modo che le persone possano verificare i risultati da soli.Una riga aggiuntiva che rappresenta una qualche forma di stato da leggere nel tuo programma, se il tuo programma ha prodotto un simile output nel round precedente. All'inizio del gioco, questa riga sarà sempre vuota. Questa riga non verrà modificata né dal codice di punteggio né da altri programmi.
Ogni programma utilizzerà quindi la propria strategia per produrre quanto segue allo standard output :
Un elenco di
K
numeri, che sono gli ID dei programmi che "prenderà 1" da questo round. Un output vuoto significa che non farà nulla.Facoltativamente, una riga aggiuntiva che rappresenta una qualche forma di stato da passare ai round successivi. Questa riga esatta verrà restituita al programma nel turno successivo.
Di seguito è riportato un esempio di input per l'inizio del gioco per un giocatore ID 3
in una partita a 4 giocatori:
4 3 0
4696634734863777023
Di seguito è riportato un esempio di input per lo stesso gioco con alcuni round già giocati:
4 3 2
(1, 2) (1, 3) (1, 4) (4, 2)
(1, 3) (2, 1) (2, 4) (3, 1) (4, 1)
4675881156406346380
Ad ogni programma verrà fornito esattamente lo stesso input per un round tranne il numero ID D
che è univoco per ciascun programma.
Di seguito è riportato un esempio di output in cui il giocatore 3
prende 1 da tutti gli altri:
1 2 4
Alla fine di tutti i round richiesti, il giocatore con il punteggio finale più alto sarà il vincitore.
Sequenza temporale
La codifica per questo torneo durerà per un totale di 7 giorni. La scadenza per la presentazione è 2014-05-09 00:00 UTC
.
Non pubblicare programmi effettivi prima di questa data: pubblica l'hash SHA256 del codice sorgente del tuo programma come impegno. Puoi modificare questo hash in qualsiasi momento prima della scadenza, ma gli impegni pubblicati dopo la scadenza non saranno accettati per il giudizio. (Si prega di utilizzare la notazione di base 64 per gli hash, poiché il mio programma di verifica sputa la base 64 ed è una notazione più compatta.)
Al termine della scadenza, avrai 1 giorno (fino a 2014-05-10 00:00 UTC
) per pubblicare il codice sorgente effettivo del tuo programma per l'invio. Se l'hash SHA256 del tuo codice sorgente pubblicato non corrisponde ad alcun hash che hai pubblicato prima della scadenza, il tuo codice non verrà accettato nel torneo.
Dopodiché, scaricherò tutte le presentazioni sul mio computer ed eseguirò tutte le voci del torneo in questo battle royale, sperando di pubblicare i risultati entro 2 giorni da allora, entro 2014-05-12 00:00 UTC
.
Accetterò la risposta con il punteggio più alto e assegnerò una taglia di +100 a quella risposta se il suo punteggio finale è maggiore di 0
.
Al termine del torneo, posterò il file seme casuale utilizzato per eseguire la competizione e le persone potrebbero iniziare a pubblicare altre soluzioni cercando di superare quelle utilizzate nel torneo. Tuttavia, non contano per l'accettazione o la generosità.
La macchina host
Eseguirò queste soluzioni su una macchina virtuale sul mio computer. Questa macchina virtuale eseguirà Ubuntu Linux 14.04, con 2 gigabyte di RAM. La mia macchina base ha un processore Intel i7-2600K a 3,40 GHz.
Requisiti
Il tuo programma deve essere scritto in una lingua per la quale esiste un compilatore o un interprete che compilerà il tuo programma ed è prontamente disponibile per l'ultima versione di Ubuntu Linux, in modo che io possa eseguire tutti gli invii e giudicarli in una macchina virtuale.
Il tuo programma non deve richiedere altro che 2.000 seconds
eseguire ogni round. Se il tuo programma si esaurisce o produce un errore, il suo output verrà considerato vuoto per quel round.
Il tuo programma deve essere deterministico; cioè, deve sempre restituire lo stesso output per lo stesso input. Sono consentite soluzioni pseudocasuali; tuttavia, la loro casualità deve dipendere dal seme casuale datogli come input e nient'altro. Il file seme è stato generato usando Python os.urandom
. Contiene un totale di 500 righe (se necessario ne verranno generate altre) e l'hash SHA256 lo è K+ics+sFq82lgiLanEnL/PABQKnn7rDAGmO48oiYxZk=
. Verrà caricato qui una volta terminato il torneo.
Impianti
Per dare il via alle cose, ci saranno quattro "piante", che rappresentano strategie ingenui iniziali. Questi giocheranno nel torneo insieme ai tuoi invii. Tuttavia, nel caso improbabile che uno di loro vinca, il punteggio più alto ottenuto da un giocatore diverso da una pianta sarà considerato il vincitore.
Per calcolare l'hash del file di ogni impianto, sostituisci ogni gruppo di 4 spazi con una scheda, dal momento che al formattatore qui non piacciono i caratteri di tabulazione.
The Lazy - non fa mai niente.
n1bnYdeb/bNDBKASWGywTRa0Ne9hMAkal3AuVZJgovI=
pass
The Greedy : ne prende sempre 1 da tutti gli altri.
+k0L8NF27b8+Xf50quRaZFFuflZhZuTCQOR5t5b0nMI=
import sys
line1 = sys.stdin.readline()
n = [int(i) for i in line1.split()]
for i in range(n[0]):
if i+1 != n[1]:
print i+1,
print
The Wrathful : prende 1 da tutti gli altri nel primo round e ne prende 1 da tutti quelli che ne hanno preso 1 nel round precedente in seguito.
Ya2dIv8TCh0zWzRfzUIdFKWj1DF9GXWhbq/uN7+CzrY=
import sys
import re
line1 = [int(i) for i in sys.stdin.readline().split()]
players = line1[0]
pid = line1[1]
rounds = line1[2]
lines = []
if rounds == 0:
for i in range(players):
if i+1 != pid:
print i+1,
print
else:
for i in range(rounds):
lines.append(sys.stdin.readline())
lastline = lines[-1]
takes = re.findall(r'\([0-9]+, [0-9]+\)', lastline)
for take in takes:
sides = [int(i) for i in re.findall(r'[0-9]+', take)]
if sides[1] == pid:
print sides[0],
print
The Envious : prende 1 dal 50% dei giocatori con il punteggio più alto attualmente escluso, arrotondando per difetto.
YhLgqrz1Cm2pEcFlsiIL4b4MX9QiTxuIOBJF+wvukNk=
import sys
import re
line1 = [int(i) for i in sys.stdin.readline().split()]
players = line1[0]
pid = line1[1]
rounds = line1[2]
lines = []
scores = [0] * players
if rounds == 0:
for i in range(players):
if i+1 != pid:
print i+1,
print
else:
for i in range(rounds):
takes = re.findall(r'\([0-9]+, [0-9]+\)', sys.stdin.readline())
for take in takes:
sides = [int(i) for i in re.findall(r'[0-9]+', take)]
scores[sides[0] - 1] += 1
scores[sides[1] - 1] -= 2
score_pairs = [(i+1, scores[i]) for i in range(players)]
score_pairs.sort(key=lambda x:(x[1], x[0]))
score_pairs.reverse()
taken = 0
j = 0
while taken < (players) / 2:
if score_pairs[j][0] != pid:
print score_pairs[j][0],
taken += 1
j += 1
In un torneo di 100 round proprio tra questi quattro, ricevono punteggi di:
Lazy: -204
Greedy: -100
Wrathful: -199
Envious: -199
Programma di valutazione
Ho pubblicato il programma del giudice che userò su Github . Scaricalo e provalo. (E magari correggere un bug o due se ne trovi uno.: P)
Al momento non ha opzioni di compilazione per nient'altro che Python. Includerò quelli in seguito - se le persone potessero contribuire con script di compilazione o interpretazione per altre lingue, sarei molto grato.
Fase 2: invio del codice sorgente
Ho pubblicato un nuovo ramo tournament
nel repository Github per il contest, contenente il file pd_rand e altre voci di impianto. Puoi pubblicare qui il tuo codice sorgente o inviarlo a quel ramo come richiesta pull.
L'ordine dei concorrenti sarà il seguente:
'begrudger'
'regular'
'patient'
'lazy'
'backstab'
'bully'
'lunatic'
'envious'
'titfortat'
'greedy'
'wrathful'
'judge'
'onepercent'
Punteggi finali
L'output del mio programma di test:
Final scores:
begrudger -2862
regular -204
patient -994
lazy -2886
backstab -1311
bully -1393
lunatic -1539
envious -2448
titfortat -985
greedy -724
wrathful -1478
judge -365
onepercent -1921
Classifica:
1. regular -204
2. judge -365
3. greedy -724
4. titfortat -985
5. patient -994
6. backstab -1311
7. bully -1393
8. wrathful -1478
9. lunatic -1539
10. onepercent -1921
11. envious -2448
12. begrudger -2862
13. lazy -2886
Quindi si scopre che il vincitore è davvero un giocatore - è The Regular, con -204 punti!
Sfortunatamente, il suo punteggio non era positivo, ma non possiamo aspettarci che in una simulazione del dilemma del prigioniero iterato in cui tutti giocano per vincere.
Alcuni risultati sorprendenti (almeno che pensavo fossero sorprendenti):
The Greedy ha segnato più di Tit per Tat e, in effetti, è generalmente più alto della maggior parte dei marcatori.
Il Judge, che doveva essere una sorta di personaggio di "moralità" (in pratica ne prendeva 1 da chiunque avesse preso 1 da qualcuno un numero superiore alla media) finì per segnare un punteggio piuttosto alto, mentre nei test di simulazione, in realtà ottenere un punteggio piuttosto basso.
E altri che (pensavo) non erano così sorprendenti:
Il paziente ha segnato ben 484 punti in più di The Wrathful. Vale davvero la pena collaborare quella prima volta.
L'uno per cento molto rapidamente non aveva quasi nessuno a calciare mentre erano giù. Sembra che l'1% sia in grado di rimanere tale solo perché hanno più giocatori nel gioco.
Ad ogni modo, ora che il torneo è finito, sentiti libero di pubblicare tutti i giocatori extra che desideri e provalo con loro usando il programma arbitrale.