UWAGA : Zwycięzcą tego konkursu jest Jack !!!. Żadne kolejne zgłoszenia nie będą akceptowane.
Oto czat tego wyzwania króla wzgórza . To mój pierwszy, więc jestem otwarty na sugestie!
Reaper to koncepcja gry opracowana przez Art of Problem Solving, która wymaga cierpliwości i chciwości. Po zmodyfikowaniu gry, aby pasowała do konkursu w stylu KOTH (dzięki @NathanMerrill i @dzaima za sugestie i ulepszenia), oto wyzwanie.
Gra działa w następujący sposób: mamy wartość znaną jako Reap, która mnoży się przez określoną stałą przy każdym tiku. Po każdym tyknięciu każdy bot ma opcję „zbierania”, co oznacza dodanie bieżącej wartości Reap do swojego wyniku i zmniejszenie Reap do 1.
Istnieje jednak ustalona liczba tyknięć, które bot musi odczekać między „zbiorem”, oraz stała liczba punktów niezbędnych do wygrania gry.
Wystarczająco proste? Oto twoje dane wejściowe:
I / O
Masz napisać funkcję w Pythonie 3, która pobiera 3 dane wejściowe. Pierwszy self
służy do odwoływania się do obiektów klasy (pokazano później). Drugi to Reap
aktualna wartość Żniwa, którą zarobiłbyś, gdybyś „Żył”. Trzecia to prevReap
lista botów, które zbierały podczas poprzedniego tyknięcia.
Inne obiekty, do których masz dostęp w swojej funkcji:
self.obj: An object for your use to store information between ticks.
self.mult: The multiplier that Reap is multiplied by each tick
self.win: The score you need to win
self.points: Your current set of points
self.waittime: The amount of ticks that you must wait between reaps during the game
self.time: The number of ticks since your last reap
self.lenBots: The number of bots (including you) in the game.
self.getRandom(): Use to produce a random number between 0 and 1.
Ty MUSI nie zmieniać żadnego z treścią tych obiektów, z wyjątkiem self.obj
.
Musisz generować, 1
aby zbierać, i cokolwiek innego (lub nic), aby nie zbierać. Zauważ, że jeśli zbierzesz, gdy nie czekałeś wystarczająco dużo tyknięć, zignoruję fakt, że postanowiłeś zbierać.
Zasady
Parametry będę używał to winning_score=10000
, multiplier=1.6-(1.2/(1+sqrt(x)))
, waittime = floor(1.5*x)
gdzie x
jest liczbą botów w KOTH.
- Gra kończy się, gdy gracz (lub wielu) osiągnie zwycięski wynik.
- Kiedy wiele botów prosi o zbieranie na raz, pierwszeństwo mają boty, które czekały dłużej (w przypadku remisów, boty, które czekały maksymalny czas wszystkie mogą zbierać i zdobywać punkty w Reap)
- Twój bot nie może zająć średnio więcej niż 100 ms przez 5 tyknięć.
- Jeśli chcesz zaimportować biblioteki, zapytaj! Spróbuję dodać dowolne biblioteki, które mogę uruchomić na mojej stacjonarnej wersji Pythona (matematyka jest już zaimportowana: możesz ją swobodnie używać)
- Wszystkie standardowe luki dla KoTH, takie jak zduplikowane boty, boty 1-up itp., Są podobnie zbanowane.
- Wszelkie boty korzystające z dowolnej losowości muszą korzystać z
getRandom
funkcji, którą podałem.
Kontroler można znaleźć w linku TIO poniżej. Aby go użyć, dodaj nazwę swojej funkcji BotList
jako ciąg, a następnie dodaj funkcję do kodu. Zmodyfikuj, multiplier
aby zmienić to, co Reap jest mnożone przez każdy tik, zmodyfikuj, winning_score
aby zmienić wynik niezbędny do zakończenia gry, i zmodyfikuj, waittime
aby zmienić liczbę tyknięć, które będą czekać między zbiorami.
Dla Twojej wygody, oto kilka przykładowych (i raczej głupich) botów. Przesyłanie botów podobnych do tych nie będzie dozwolone. Pokazują jednak, jak działa kontroler.
def Greedybot(self,Reap, prevReap):
return 1
def Randombot(self,Reap, prevReap):
if self.obj == None:
self.obj=[]
self.obj.append(prevReap)
if self.getRandom()>0.5:
return 1
Dla zainteresowanych, oto Kontroler z wbudowanymi 15 zgłoszeniami: Wypróbuj online
OSTATECZNE REZULTATY
WOO SĄ OSTATECZNIE TUTAJ! Sprawdź powyższy link TIO, aby zobaczyć, jakiego kodu użyłem do wygenerowania końcowej klasyfikacji. Wyniki nie są wyjątkowo interesujące. Wyniki ponad 1000 przebiegów, które wykonałem z różnymi losowymi nasionami
1000 wins - Jack
0 wins - everyone else
Gratulacje dla zwycięzcy nagrody Bount Jack! (alias @Renzeee)
źródło
len(BotList)
?25
botów w grze. Najpierw jednak trochę poczekam, by zobaczyć boty innych ludzi. Rushabh Mehta , czy będzie ostateczny termin / data, kiedy wszystkie boty zostaną uruchomione i zostanie wyłoniony zwycięzca?Odpowiedzi:
Niezdecydowany Twitchy Mess
Ten bot wykonuje najpierw zwykłe kontrole (czy mogę zbierać, czy mogę wygrać?), A następnie szuka wartości docelowej, zanim zacznie zbierać. Jest jednak niezdecydowany, więc po osiągnięciu celu zastanawia się, jak długo może poczekać i nie zbiera natychmiast. Ponadto jest niepewny, więc może przypadkowo „nacisnąć przycisk” i zebrać się przed celem.
Ciekawostka: w zasadzie gram jako żniwiarz jako człowiek.
źródło
Snajper
Bot napędzany złośliwością. Śledzi czasy odnowienia i wyniki przeciwnika. Próby powstrzymania innych przed wygraną. Prawie nigdy tak naprawdę nie wygrywa, ale sprawia, że gra jest frustrująca dla innych.
EDYTOWAĆ:
Jeśli nikt nie jest> = 70% zwycięskiego wyniku:
Jeśli co najmniej połowa innych użytkowników jest w trakcie odnawiania, spróbuj zebrać.Utrudnia to atakowanie określonych przeciwników, dlatego został usunięty.Jeśli ktoś JEST> = 70% zwycięskiego wyniku:
Znudzony
Dla zabawy ten bot został przywieziony przez przyjaciela i tak naprawdę nie chce tu być. Rzucają k16, dopóki nie otrzymają liczby od 1 do 9, a następnie próbują zbierać za każdym razem, gdy liczba zawiera wybraną cyfrę. (Poszukiwanie d10 zakłóciłoby grę, która jest niegrzeczna, a 0 jest po prostu zbyt łatwe!)
źródło
self.obj.opponents[opponent]["time"] += 1
w pierwszej pętli for iself.obj.lastReap
na końcu drugiej pętli for. Poza tym fajne pomysły. Jestem ciekawy, jak to zadziałałoby z wieloma innymi botami. Kiedy używam wielu chciwych i losowych botów, po prostu zbierze jak najszybciej, ponieważ przez większość czasu połowa botów nie może czerpać. Ale oczywiście nie są to realistyczni konkurenci.Jacek
Jest to prosty bot z 4 zasadami:
Zoptymalizowałem 3 tiki w porównaniu do obecnych istniejących botów (Sniper, grim_reaper, Every50, mess, BetterRandom, Averager, trochę więcej).
Próbowałem pozostać przy moim starym rozwiązaniu (5 tyknięć), ale także czerpać, jeśli nie czerpiesz więcej niż X tyknięć, a następnie czerpać po przejściu mniejszej liczby tyknięć podczas braku zbierania (tj. 5, jeśli czekasz dłużej niż ja .waittime + 5, również zbiera, jeśli nie został zebrany za 4 tiki). Ale to nie poprawiło się po prostu zawsze zbierając po 4 tyknięciach zamiast 5.
źródło
Co 50
Te boty będą zbierać za każdym razem, gdy ich
Reap
ilość przekroczy 50.Dlaczego 50
Jeśli założę, że w grze będzie 25 botów, oznacza to, że
multiplier = 1.6-(1.2/(1+sqrt(25))) = 1.4
iwaittime = floor(1.5*25) = 37
. Od początkuReap
zaczyna1
się tak:Jak widać, osiąga ponad 50 po 13 tyknięciach. Ponieważ
Reap
będzie zresetować do 1 za każdym razem, gdy zbiera bot, awaittime
dla bota, który zbiera wynosi 37, prawdopodobieństwo a zbiera bot prędzej niż później jest dość wysokie, zwłaszcza z botami podobnej do przykładuGreedyBot
, który będzie czerpać jak najszybciej ichwaittime
Is dostępne ponownie. Na początku chciałem zrobić 200, czyli 17 tyknięcie, nieco w połowie z 37 tyknięć w czasie oczekiwania, ale przy założeniu, że w grze jest 25 botów, istnieje duża szansa, że ktoś innyReap
mnie porwie . Więc obniżyłem go do 50. To wciąż ładna zaokrąglona liczba, ale szczególnie dlatego, że jest to 13. tyknięcie (z 25 botami), a 13 i „zbieranie” również pasują trochę do tego samego „złego” gatunku.Kod:
Kod jest śmiesznie trywialny ..
Uwagi:
Ten bot jest dość zły z niską liczbą botów w grze. Na razie zostawię to, a może będę lepszym botem obliczającym najlepszy czas
Reap
. Przy wyjątkowo niskiej liczbie botów w grzewaittime
jest również znacznie niższa, więc nawetGreedyBot
może dość łatwo wygrać z tego bota, jeśliwaittime
jest wystarczająco niski.Mam nadzieję, że więcej osób doda o wiele więcej botów. ; p
źródło
def Every49(self, Reap, prevReap): return Reap > 49
Twój ruch.int
ominąć nierówność, ponieważ 1 to prawdziwe polecenieTrue
jawnie to jawić1
. Wyobrażałem sobie, żeTrue == 1
czek nadal będzie wracałTrue
dla mojego bota dodającego go do listReapers
w twojejnext
funkcji, ale dodałem rzutowanie do int tak jak sugerowałeś.Uśrednianie
Ten bot próbuje zbierać za każdym razem, gdy aktualna wartość Reap jest wyższa niż średnia wartość Reapped.
źródło
Ponury Żniwiarz
Bot utrzymuje bieżącą średnią wartości wszystkich poprzednich zbiorów, a także czas oczekiwania każdego bota. Zbiera, gdy czeka dłużej niż 3/4 innych botów, a żniwa są co najmniej 3/4 wielkości przeciętnego dotychczasowego żniwa. Celem jest zebranie dużej ilości żniw o niskim ryzyku w rozsądnej wielkości.
Edycja: Naprawiono niektóre żenujące błędy składniowe.
Wypróbuj online
źródło
self.obj.reaps
zamiastself.reaps
iself.obj
zamiastself.object
iprevReap
zamiastprevLeap
i add () poself.obj.players.values
dwa razy. I myślę, żeself.obj.reaps = []
nie zadziała, chyba żeself.obj
jest przedmiotem. Nie jestem do końca pewien, czy wszystko działa nadal zgodnie z przeznaczeniem i czy wszystko, co powiedziałem, jest prawdą, ale po tych zmianach i użyciu fałszywego obiektu,self.obj
gdy jeszcze nie istnieje, kod kompiluje się dla mnie.class Object(object):
[newline]pass
na górze i użyłemself.obj = Object()
wif not hasattr(..)
(jeśli dobrze pamiętam).BetterRandom
Bot opiera się na założeniu, że szansa na zbieranie powinna być proporcjonalna do wielkości zbieranych plonów, ponieważ punkt jest punktem, bez względu na to, kiedy zostanie zdobyty. Zawsze istnieje bardzo niewielka szansa na czerpanie korzyści, dzięki czemu zachowanie można wykorzystać. Najpierw pomyślałem, że będzie to wprost proporcjonalne i założyłem, że stała proporcjonalności będzie w pobliżu
1/mult^waittime
(maksymalne czerpanie przy założeniu, że przynajmniej jeden bot gra zachłanny) po uruchomieniu niektórych symulacji stwierdziłem, że była to rzeczywiście optymalna stała. Ale bot wciąż był lepszy od Randoma, więc doszedłem do wniosku, że relacja nie była wprost proporcjonalna i dodałem stałą, aby obliczyć, jaka była relacja. Po kilku symulacjach stwierdziłem, że w porównaniu z moim testem zestaw botów-1.5
był optymalny. W rzeczywistości odpowiada to odwrotnie proporcjonalnemu stosunkowi między szansą zbierania areap*sqrt(reap)
co jest zaskakujące. Podejrzewam, że jest to w dużej mierze zależne od konkretnych botów, więc wersja tego bota, która oblicza K podczas gry, byłaby lepsza. (Ale nie wiem, czy możesz korzystać z danych z poprzednich rund).EDYCJA: Zrobiłem program, aby automatycznie znaleźć rodzaj proporcjonalności. Na zestawie testowym
["myBot("+str(k)+")","Randombot","Greedybot","Every50","Jack","grim_reaper","Averager","mess"]
znalazłem nową wartość.źródło
(reap/self.mult**self.waittime)**-0.810192835
jest zawsze powyżej 1, tzn. Self.getRandom () nigdy nie jest wyższy.self.obj
jest. Aby zobaczyć kilka przykładów, jak go używać, spójrz na niektóre inne boty, które go używają.Cel
Moje szanse na wygraną z bałaganem są prawie zerowe, więc czas zepsuć wszystkie inne boty na jak najwięcej sposobów! :)
Ten bot działa podobnie jak snajper. Ilekroć ktoś zbiera, wybiera losowy cel od tego, kto zbierze. Następnie po prostu czeka, aż ten cel prawie znów zbierze żniwo i go wycina. Nie zmienia to jednak ostrości - po wybraniu i zablokowaniu nie możesz uciec :)
źródło
EveryN
Chyba czas na mojego drugiego bota tuż przed terminem.
Ten bot:
n
rund, gdzien
oblicza się za pomocąn = 3 + ceil(self.waittime / self.lenBots)
Kod:
Nie programuję zbyt często w Pythonie, więc jeśli zauważysz jakieś błędy, daj mi znać.
źródło
subsequentRoundsWithoutReaps
doroundsWithoutReaps
; użyto małych liter ze znakami podkreślenia dla nazwy metody; i usunąłem nawias w instrukcjach if. Dzięki.prevReap
alenBots
i takie i zakładane zmienne są CamelCase jak w Javie. ;) Ach cóż, bez względu na to, jakiego przypadku użyjemy, i tak powinno działać. 2 zamiast 4 wciętych spacji prawdopodobnie spowodowałoby jednak pewne problemy, więc dziękuję w obu przypadkach.W toku: Mój projekt rozszerzenia T4T na każdy otwarty KOTH.
Wet za wet
Tit for n Tats
Kevin
Tylko po to, abyś był na nogach.
źródło
self.last
nie jest rzeczą, ale możeszself.obj.last
coś zrobić ! W każdym razie dodam wszystkie trzy twoje boty do memów +1Przeciętny Joe
Zainspirował mnie Averager i stworzyłem bota, który oblicza średnią liczbę obrotów, zanim ktoś zbierze, i spróbuje zebrać jedną turę przed tym.
źródło
Mocno zakodowane
Tak to jest.
Zamiast uśredniania wyników z przeszłości, należy użyć wstępnie obliczonej średniej dla typowego przebiegu. Z czasem i tak nie będzie lepiej.
źródło