To zadanie jest częścią First Periodic Premier Programming Puzzle Push i ma na celu demonstrację nowej propozycji typu wyzwanie króla wzgórza .
Zadanie polega na napisaniu programu, który lepiej rozwiąże dylemat więźnia niż inni uczestnicy.
Spójrz, Vinny. Znamy twojego kolegę z celi - jak on się nazywa? Tak, McWongski, Nippo-irlandzko-ukraiński gangster - coś knuje i wiesz, co to jest.
Próbujemy być tutaj mili, Vinnie. Daje ci szansę.
Jeśli powiesz nam, co planuje, zobaczymy, że dostałeś dobre zadanie.
A jeśli nie ...
Zasady gry
- Konkurs składa się z pełnego rundy (wszystkie możliwe parowania) dwóch zawodników jednocześnie (w tym gry własnej).
- Rozgrywa się 100 rund między każdą parą
- W każdej rundzie każdy gracz jest proszony o wybór pomiędzy współpracą z innym graczem lub zdradzeniem go, bez znajomości intencji innych graczy w tej sprawie, ale z pamięcią wyników poprzednich rund rozgrywanych z tym przeciwnikiem.
- Punkty są przyznawane za każdą rundę na podstawie połączonego wyboru. Jeśli obaj gracze współpracują, każdy otrzymuje 2 punkty. Wzajemna zdrada daje po 1 punkcie. W przypadku mieszanym zdradzający gracz otrzymuje 4 punkty, a kooperator zostaje ukarany 1.
- „Oficjalny” mecz zostanie rozegrany nie wcześniej niż 10 dni po opublikowaniu wszystkich zgłoszeń, które mogę zabrać do pracy i zostaną użyte do wybrania „zaakceptowanego” zwycięzcy. Mam system Mac OS 10.5, więc rozwiązania POSIX powinny działać, ale istnieją linuksizmy, które nie działają. Podobnie nie mam wsparcia dla interfejsu API win32. Chcę podjąć podstawowy wysiłek, aby zainstalować rzeczy, ale jest pewien limit. Granice mojego systemu w żaden sposób nie reprezentują granic akceptowalnych odpowiedzi, po prostu te, które zostaną uwzględnione w „oficjalnym” meczu.
Interfejs programisty
- Wpisy powinny mieć postać programów, które można uruchamiać z wiersza poleceń; decyzja musi być (jedynym!) wyjściem programu na standardowe wyjście. Historia poprzednich rund z tym przeciwnikiem zostanie przedstawiona jako argument wiersza poleceń.
- Wyjście to „c” (dla clam up ) lub „t” (dla Tell all ).
- Historia jest pojedynczym ciągiem znaków reprezentujących poprzednie rundy, przy czym najnowsze rundy pojawiają się najwcześniej w ciągu. Postacie są
- „K” (dla zachowania wiary oznacza wzajemną współpracę)
- „R” (dla szczura b @ st @ rd mnie wyprzedał! )
- „S” (dla frajera! Co oznacza, że skorzystałeś ze zdrady)
- „E” (bo wszyscy szukają numer jeden na wzajemnej zdradzie)
Wspornik
Autor zapewni czterech graczy
- Anioł - zawsze współpracuje
- Diabeł - zawsze mówi
- TitForTat - Współpracuje w pierwszej rundzie, a następnie zawsze robi to, co zrobił w ostatniej rundzie
- Losowo - 50/50
do którego dodam wszystkie wpisy, które mogę uruchomić.
Całkowity wynik będzie sumą punktów przeciwko wszystkim przeciwnikom (w tym samobójstwom tylko raz i przy użyciu średniego wyniku).
Uczestnicy
(aktualny od 2 maja 2011 r. 7:00)
Tajny uścisk dłoni | Pocisk anty-T42T | Nieufność (wariant) | Anti-Handshake | Mały Lisper | Konwergencja | Rekin | Probabimatic | Pavlov - Win Stay, Lose Switch | Honor Wśród Złodziei | Pomóż wampirowi | Druid | Mały Schemer | Bygones | Tit for Two Tats | Simpleton |
Markier
#! /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
- Skargi dotyczące mojego okropnego pytona są mile widziane, ponieważ jestem pewien, że jest to do bani więcej niż jeden sposób
- Mile widziane poprawki błędów
Dziennik zmian strzelców:
- Wydrukuj posortowanych graczy i wyniki oraz ogłosić zwycięzcę (4/29, Casey)
- Opcjonalnie uruchom wiele turniejów (
./score warriors/ num_tournaments)
) domyślnie = 1, wykryj i skompiluj źródła python (4/29, Casey) - Napraw szczególnie głupi błąd, w którym drugiemu graczowi podawano nieprawidłową historię. (4/30, dmckee; dzięki Josh)
Początkowi wojownicy
Przykładowo, aby wyniki mogły zostać zweryfikowane
Anioł
#include <stdio.h>
int main(int argc, char**argv){
printf("c\n");
return 0;
}
lub
#!/bin/sh
echo c
lub
#!/usr/bin/python
print 'c'
Diabeł
#include <stdio.h>
int main(int argc, char**argv){
printf("t\n");
return 0;
}
Losowy
#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;
}
Należy pamiętać, że sekretarz może wielokrotnie przywoływać wojownika w ciągu jednej sekundy, dlatego należy podjąć poważny wysiłek, aby zapewnić losowość wyników, jeśli czas zostanie wykorzystany do zainicjowania 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;
}
Pierwszy, który faktycznie ma coś wspólnego z historią.
Uruchamianie sekretarza tylko na podanych wojownikach daje
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)
Ten diabeł jest rzemieślnikiem, a sympatyczni faceci najwyraźniej wchodzą ostatni.
Wyniki
„oficjalnego” biegu
('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
źródło
return (s1, L1+h1), (s2, L2+h1)
nareturn (s1, L1+h1), (s2, L2+h2)
[UwagaL2+h2
zamiastL2+h1
na końcu]? // Błąd wycinania i wklejania lub coś równie idiotycznego. Do licha!Odpowiedzi:
Stopniowy
Strategia ta oparta jest na dokumencie Beaufils, Delahaye i Mathieu . Moje C naprawdę nie jest najlepsze, więc jeśli ktoś ma jakieś sugestie dotyczące ulepszenia / przyspieszenia kodu, daj mi znać!
[Edytuj] Warto zauważyć, że Gradual został zaprojektowany jako strategia, która przewyższa Tit dla Tat. Ma podobne właściwości, ponieważ jest skłonny do współpracy i odwetu przeciwko wadliwemu przeciwnikowi. W przeciwieństwie do Tit for Tat, który ma tylko pamięć ostatniej rozegranej rundy, Gradual zapamięta całkowitą interakcję i zmieni liczbę przypadków, w których przeciwnik do tej pory pokonał. Później jednak znów zaoferuje wzajemną współpracę.
Jak zwykle wydajność strategii zależy nieco od składu innych strategii. Również oryginalny papier nie był tak naprawdę jasny w niektórych szczegółach.
źródło
Tajny uścisk dłoni
Strategia polega na poświęceniu pierwszych 10 rund w celu wykonania „tajnego” uścisku dłoni. Jeśli jestem w komórce, rozpoznaję historię pierwszych 10 ruchów i zakładam czapkę Anioła na resztę gry. Gdy tylko uznaję, że mój kolega z celi nie jest sobą, przekształcam się w diabła, próbując wykorzystać zbyt kooperatywnych towarzyszy.
To, czy poświęcenie pierwszych 10 rund pozwoli mi wyrównać samego Diabła, zależy w dużej mierze od liczby wpisów. Aby zminimalizować uszkodzenia, tylko 3 współpracowników pojawiają się w uścisku dłoni.
Edycja: TAGMATCH dynamiczny teraz, aby zapobiec głupim błędom, takim jak zmiana tylko jednego z nich, dzięki czemu mogę w pewnym momencie w przyszłości włączyć TAG dynamiczny.
Edycja 2: Teraz losowo generuje znacznik przy pierwszym uruchomieniu i zapisuje go w pliku określonym przez
sys.argv[0]
(.pyc
zastąpiony przez,.py
więc przechodzi do kodu, a nie kodu bajtowego, pliku). Myślę, że to jedyna informacja, którą mają wszystkie moje instancje, której nie ma nikt inny, więc wydaje się, że to jedyna opcja unikania pasożytów.źródło
TAG
że grałem wstecz. Jednak czy nie powinnoTAGMATCH
być „KEEEKEEEKE”?"".join({('c', 'c'):'K', ('t', 't'): 'E'}[moves] for moves in zip(TAG, TAG))
.py
pliki w poszukiwaniu twojego kodu i wyodrębnić TAG. Nie zrobię tego jednak w C ...Mały Lisper
Diabeł
Rozważ następujące formatowanie (Player1, Player2)
Zakładając, że P2 jest diabłem, nie ma sposobu, aby diabeł kiedykolwiek stracił punkty, w rzeczywistości najgorsze, co może zrobić, to zdobyć tylko jeden punkt. Wobec czysto losowego przeciwnika najgorszym możliwym wynikiem diabła będzie dokładnie (5/2) * n, gdzie n jest liczbą rozegranych „gier”. Jego najgorszy przypadek jest przeciwko samemu sobie, gdzie jego wynik będzie równy n, a jego najlepszy przypadek będzie przeciwko aniołowi, który będzie równy 4 * n
Twierdz: optymalny_strat = diabeł
to jest turniej. Dźgnięcie w plecy mojego kolegi z komórki jest znacznie lepszą strategią niż współpraca, ponieważ pomaga MOJEMU WYNIKU więcej (+4). BONUS - zostaje uderzony (-1)! Jeśli wystawię mu szyję, mogę zyskać (+2) i stracić (-1). Dlatego statystycznie dźgnięcie w plecy jest nagradzane.
Ale czy to jest optymalne?
Nie ma powodu, aby NIGDY (w ramach tego systemu punktacji) współpracować.
W systemie KOTH maksymalizacja zwrotów jest niezbędna. Nawet jeśli masz dwa boty, które są doskonale zsynchronizowane i współpracują, wyniki ich poszczególnych osób nadal będą zwiększone tylko o 200 punktów za ich sportowe umiejętności. Z drugiej strony, diabeł zdobędzie co najmniej 100 punktów, przy średnim przypadku 200 i maksymalnie 400, i kosztuje przeciwników do 100 punktów każdy! Tak więc praktycznie diabeł naprawdę osiąga średnią liczbę gier wynoszącą 300, zwiększając do 500.
Konkluzja - czas pokaże
Dla mnie wygląda na to, że punktacja powinna zostać ponownie rozważona, aby diabeł nie wykorzystał dnia. Zwiększenie wyniku współpracy do 3 wszystko może to zrobić. Można jednak wykryć diabły i uniemożliwić im zdobycie pełnych 400 punktów, jak pokazują pavlov i złośliwość. Czy mogę udowodnić, że któryś z nich zbierze wystarczającą liczbę punktów, aby uzasadnić swoją wiarę? Nie. Wszystko to zależy od ostatecznego pola rywali.
I proszę zrób najgorsze z tego postu. Chcę napisać o tym mój starszy artykuł, kiedy wszystko zostanie powiedziane i zrobione.
Historia wersji
OFICJALNA WERSJA LISPER
ROZWÓJ WERSJI LISPER
źródło
fink install clisp
:: wielokrotne stukanie palcami ::There is no reason to EVER (under this scoring system) co-operate
jest tylko w połowie poprawne. Jeśli wiesz, że twój przeciwnik nie bierze pod uwagę historii (anioł, diabeł, losowy), zawsze powinieneś uciec. Jeśli twój przeciwnik bierze pod uwagę historię i możesz zsynchronizować, możesz zrobić to lepiej. Mam kilka pomysłów, które koncentrują się na wykrywaniu, czy przeciwnik jest racjonalny czy ponadnarodowy.(random 20)
daje 2, 5 lub 8,(/ (+1 rand-num) 10)
wynosi 0,3, 0,6, 0,9, a reszta dzielenia z 0,3 wynosi 0; tak(floor *dbag* *margin*)
umieraNieufność (wariant)
Ten wyszedł pierwszy raz w moich testach lata temu (wtedy byłem w 11 klasie i napisałem drobną tezę na ten temat, stosując strategie opracowane również przez innych uczniów). Zaczyna się od sekwencji
tcc
(i potem gra jak Tit dla Tat.Przepraszamy za ten okropny kod; jeśli ktoś może to skrócić, choć nie do końca gra w golfa, byłbym wdzięczny :-)
źródło
case 1: case2: printf(...); break;
. A gcc chce jednoznacznej deklaracjistring.h
użyciastrlen
. W każdym razie mam to uruchomione.Popen(p+" "+h,stdout=subprocess.PIPE,shell=True)
kiedyh = ''
. Zgadujęargc=1
.Pocisk anty-T42T
Radzi sobie dość dobrze w stosunku do podstawowego zestawu wojowników: zabija Anioła, lekko pobitego przez Diabła (ale utrzymuje niski wynik), generalnie pokonuje RAND ręcznie, a po prostu ledwo pokonuje Tit dla Tat. Radzi sobie źle, gdy gra przeciwko sobie.
źródło
Konwergencja
Początkowo fajnie, potem gra losowo, mając oko na historię przeciwnika.
Próbowałem wyważyć wagę historii, ale nie odpowiednio ją zoptymalizowałem.
źródło
Rekin
Radzi sobie całkiem dobrze w stosunku do podstawowego składu.
źródło
Pavlov - Win Stay, Lose Switch
W pierwszej turze współpracuje, a następnie współpracuje wtedy i tylko wtedy, gdy obaj gracze wybrali ten sam wybór w poprzednim ruchu.
źródło
hist[0]
(hist[-1]
zawsze pierwszy ruch w rundzie)?Honor wśród złodziei
Pamiętaj, że
THIEVES_CANT
jest to w zasadzie uścisk dłoni, choć pojawi się tylko podczas gry przeciwko kooperatorowi. Jednak pozwala uniknąć problemu pasożyta, sprawdzając, czy nie ma późniejszych krzyżówek. Radzi sobie całkiem dobrze w stosunku do podstawowego składu.źródło
„Probabimatic”
Zaczyna od współpracy, a następnie wybiera dowolną opcję, która daje najwyższą oczekiwaną wartość. Prosty.
Kiedyś zaczynało się od współpracy, ale teraz wydaje się, że defektowanie faktycznie działa lepiej. EDYCJA: Och, czekaj, tak naprawdę nie.
źródło
for (char c = *str;
na,char c; for (c = *str;
gcc skompiluje to bez narzekania, że należy go przełączyć w tryb C99.Hyperrational Wasp
Zaimplementowano w Javie, ponieważ nie byłem pewien, jak skomplikowane będą struktury danych. Jeśli jest to dla kogoś problem, to myślę, że mogę go przesłać, aby uderzyć bez zbyt wielu problemów, ponieważ w końcu tak naprawdę używa tylko prostych tablic asocjacyjnych.
Uwaga : Usunąłem to z pakietu zgodnie z najnowszą wersją mojej poprawki do systemu oceniającego do obsługi Javy. Jeśli chcesz opublikować rozwiązanie Java, które korzysta z wewnętrznych klas, musisz załatać łatkę.
Zmiany, które wprowadziłem w sekrecie, aby to uruchomić, to:
Dzięki @rmckenzie za złożenie mojej funkcji pretendenta.
źródło
Exception in thread "main" java.lang.NoClassDefFoundError: //warriors/HyperrationalWasp Caused by: java.lang.ClassNotFoundException: ..warriors.HyperrationalWasp at java.net.URLClassLoader$1.run(URLClassLoader.java:217) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:205) at java.lang.ClassLoader.loadClass(ClassLoader.java:321) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Soft_majo
Ach, kolejna standardowa strategia, tylko po to, by ukończyć skład.
Ten wybiera ruch, który przeciwnik wykonał najwięcej; jeśli równa, to współpracuje.
źródło
Losowy frajer
Ten zada się, jeśli przeciwnik zbyt często defekuje (próg), ale od czasu do czasu spróbuje dźgnąć w plecy.
Nieźle sobie radzi ze wszystkimi oprócz graczy Java i Lisp (których nie mogę uruchomić, ponieważ ani Java, ani Lisp nie są uruchomione na maszynie testowej); przynajmniej przez większość czasu.
źródło
BYGONES
Jak
bygones
dotąd nie wypracowałem najlepszej wartości . Nie spodziewam się, że będzie to zwycięska strategia, ale interesuje mnie wykonanie strategii podobnej do tego, co uważam za „dobre” w prawdziwym życiu. Przyszła zmiana może również obejmować sprawdzenie liczby wzajemnych usterek.źródło
Pomóż wampirowi
W porównaniu z sobą ma zabawnie asymetryczny wynik. Gdyby tylko to rozwiązanie można było zastosować w prawdziwym życiu.
źródło
druid
Radzi sobie dobrze w stosunku do podstawowego składu.
źródło
Prostak
Nie przeszkadza w stosunku do podstawowego składu.
źródło
Mały Schemer
Słabo sprawdza się w stosunku do zestawu podstawowego, ale całkiem dobrze w stosunku do celu. Oczywiście nie napisane w schemacie.
źródło
Sikora na dwa taty
inny stary faworyt
źródło
sys.exit(0)
? Lub po prostu pozwól mu skończyć. Edycja: Również pierwsze wywołanie do twojego programu jest bez historii, co powoduje, żeIndexError
to robiszargv[1]
.len(history)<2
klauzulę, ponieważ ta ostatnia wygląda jakelse
część.return
specjalnie dla mnie !