W tym wyzwaniu zmierzysz się z hałaśliwym, powtarzającym się dylematem więźnia.
W dylemat więźnia jest scenariusz, w teorii gier, gdzie istnieją dwa graczy, każdy z dwóch opcji: współpracuje lub wada. Każdy gracz radzi sobie lepiej, jeśli ma wadę, niż gdyby współpracował, ale obaj gracze wolą wynik, w którym obaj gracze współpracują, niż ten, w którym obaj grają.
Dylemat iterowanego więźnia to ta sama gra, tyle że wielokrotnie grasz przeciwko temu samemu przeciwnikowi i wiesz, w co grał Twój przeciwnik w przeszłości. Twoim celem jest zawsze zdobycie jak najwyższego wyniku, niezależnie od tego, jak robi to twój przeciwnik.
Hałaśliwy iterowany dylemat więźnia wprowadza pewne zakłócenia w komunikacji. Twoja wiedza o tym, w co grał Twój przeciwnik w przeszłości, wprowadzi trochę hałasu. Dowiesz się również, jakie ruchy wykonałeś w przeszłości. Poziom hałasu jest stały w trakcie rundy przeciwko temu samemu przeciwnikowi, ale różny dla różnych rund.
Wyzwanie
W tym wyzwaniu napiszesz program w języku Python 3, który rozwiąże dylemat hałaśliwego iterowanego więźnia.
Twój program otrzyma trzy dane wejściowe:
Twoje własne ruchy, bez losowych rzutów.
Ruchy przeciwnika, z zastosowaniem losowych rzutów.
Zmienna stanu, która zaczyna się jako pusta lista w każdej rundzie i którą możesz zmodyfikować, jeśli chcesz. Możesz to zignorować, jeśli nie chcesz go używać.
Twój program powinien wysyłać dane 'c'
do współpracy lub 'd'
do defektu.
Na przykład, oto program, który współpracuje, jeśli przeciwnik współpracował przez co najmniej 60% czasu w przeszłości, po zastosowaniu losowych rzutów i dla pierwszych 10 rzutów:
def threshold(my_plays, their_flipped_plays, state):
if len(their_flipped_plays) < 10:
return 'c'
opp_c_freq = their_flipped_plays.count('c')/len(their_flipped_plays)
if opp_c_freq > 0.6:
return 'c'
else:
return 'd'
Jeśli nie znasz języka Python, napisz swoje zgłoszenie w pseudokodzie, a ktoś (ja lub inny członek witryny) może utworzyć odpowiedni program w języku Python.
Rozgrywka
Turniej można znaleźć tutaj: noisy-game . Uruchom, noisy-game.py
aby uruchomić turniej. Będę aktualizować to repozytorium o nowe zgłoszenia. Przykładowe programy można znaleźć w basic.py
.
Ogólny wynik programu to suma jego wyników w ponad 100 grach.
Gra składa się z pojedynczych rund każdego gracza przeciwko każdemu graczowi, w tym sobie. Pojedynek składa się ze 100 rund. Runda składa się z 300 ruchów, z których każdy wymaga wykonania 'c'
lub 'd'
.
Twoje zgłoszenie spowoduje rozegranie pojedynku z każdym zgłoszeniem, w tym własnym. Każdy pojedynek będzie się składał ze 100 rund. Podczas każdej rundy prawdopodobieństwo odwrócenia będzie losowo wybierane równomiernie [0, 0.5]
.
Każda runda będzie się składać z 300 ruchów. Przy każdym ruchu oba programy otrzymają wszystkie poprzednie odtworzenia, które próbowały, i wszystkie poprzednie odtworzenia, które wykonał drugi program, po zastosowaniu odwrotności, oraz zmienną stanu, która jest zmienną listą, którą program może modyfikować, jeśli chce. Programy wygenerują swoje ruchy.
Ruchy są punktowane w następujący sposób: Jeśli program zagra 'c'
, program przeciwny otrzymuje 2 punkty. Jeśli jakiś program gra 'd'
, ten program otrzymuje 1 punkt.
Następnie każdy ruch jest odwracany niezależnie z prawdopodobieństwem równym prawdopodobieństwu przewrócenia i zapisywany do pokazania przeciwnikowi.
Po rozegraniu wszystkich rund sumujemy liczbę punktów, jaką każdy gracz otrzymał w każdym pojedynku. Następnie wykorzystujemy następujący system punktacji do obliczenia wyniku każdego gracza w grze. Ta punktacja jest przeprowadzana po zakończeniu wszystkich pojedynków.
Punktacja
Wykorzystamy ewolucyjną punktację. Każdy program zaczyna się od równej wagi. Następnie wagi są aktualizowane w następujący sposób, dla 100 iteracji, z wykorzystaniem sum punktowych z gry:
Nowa waga każdego programu jest proporcjonalna do iloczynu jego poprzedniej wagi i jego średniej sumy punktów, ważonej wagami przeciwników.
Zastosowano 100 takich aktualizacji, a ostateczne wagi są wynikiem każdego programu dla tego przebiegu gry.
Ogólne wyniki będą sumą ponad 100 przebiegów gry.
Gracze otrzymają wszystkie prawidłowe odpowiedzi na to wyzwanie oraz sześć podstawowych programów, które pomogą nam zacząć.
Ostrzeżenia
Nie modyfikuj wejść. Nie próbuj wpływać na wykonanie jakiegokolwiek innego programu, z wyjątkiem współpracy lub uszkodzenia. Nie składaj ofiarnego poddania się, które usiłuje rozpoznać kolejne poddanie się i przynieść korzyści przeciwnikowi na własny koszt. Standardowe luki są zabronione.
EDYCJA: Zgłoszenia nie mogą dokładnie powielać żadnego z podstawowych programów ani żadnego wcześniejszego zgłoszenia.
Jeśli masz jakieś pytania, możesz je zadać.
Aktualne wyniki
nicht_genug: 40.6311
stealer: 37.1416
enough: 14.4443
wait_for_50: 6.947
threshold: 0.406784
buckets: 0.202875
change_of_heart: 0.0996783
exploit_threshold: 0.0670485
kickback: 0.0313357
tit_for_stat: 0.0141368
decaying_memory: 0.00907645
tit_for_whoops: 0.00211803
slider: 0.00167053
trickster: 0.000654875
sounder: 0.000427348
tit_for_tat: 9.12471e-05
stubborn_stumbler: 6.92879e-05
tit_for_time: 2.82541e-05
jedi2sith: 2.0768e-05
cooperate: 1.86291e-05
everyThree: 1.04843e-05
somewhat_naive: 4.46701e-06
just_noise: 1.41564e-06
growing_distrust: 5.32521e-08
goldfish: 4.28982e-09
vengeful: 2.74267e-09
defect: 3.71295e-10
alternate: 2.09372e-20
random_player: 6.74361e-21
Wyniki zawierające tylko odpowiedzi na to pytanie i podstawowe programy, które ignorują grę przeciwnika:
nicht_genug: 39.3907
stealer: 33.7864
enough: 20.9032
wait_for_50: 5.60007
buckets: 0.174457
kickback: 0.0686975
change_of_heart: 0.027396
tit_for_stat: 0.024522
decaying_memory: 0.0193272
tit_for_whoops: 0.00284842
slider: 0.00153227
sounder: 0.000472289
trickster: 0.000297515
stubborn_stumbler: 3.76073e-05
cooperate: 3.46865e-05
tit_for_time: 2.42263e-05
everyThree: 2.06095e-05
jedi2sith: 1.62591e-05
somewhat_naive: 4.20785e-06
just_noise: 1.18372e-06
growing_distrust: 6.17619e-08
vengeful: 3.61213e-09
goldfish: 3.5746e-09
defect: 4.92581e-10
alternate: 6.96497e-20
random_player: 1.49879e-20
Zwycięski
Konkurs będzie otwarty przez czas nieokreślony, ponieważ publikowane będą nowe zgłoszenia. Ogłaszam jednak zwycięzcę (akceptuję odpowiedź) na podstawie wyników 1 miesiąc po opublikowaniu tego pytania.
exploit_threshold()
kilka razy jako exploit_threshold1()
itp. i dodałem je do players
listy. Dlaczego otrzymuję bardzo różne wyniki dla identycznych strategii?