Ostateczny wynik
Konkurs się skończył. Gratulacje dla hard_coded
!
Kilka interesujących faktów:
W 31600 z 40920 aukcji (77,2%) zwycięzca pierwszej rundy wygrał najwięcej rund na tej aukcji.
Jeśli w konkursie uwzględnione zostaną przykładowe boty, dziewięć najlepszych miejsc nie zmieni się inaczej
AverageMine
iheurist
zamieni swoje pozycje.10 najlepszych wyników na aukcji:
[2, 2, 3, 3] 16637
[0, 3, 3, 4] 7186
[1, 3, 3, 3] 6217
[1, 2, 3, 4] 4561
[0, 1, 4, 5] 1148
[0, 2, 4, 4] 1111
[2, 2, 2, 4] 765
[0, 2, 3, 5] 593
[1, 1, 4, 4] 471
[0, 0, 5, 5] 462
Ilość Tie (numer aukcji, że i-tej rundzie nie miał zwycięzcę)
[719, 126, 25, 36, 15, 58, 10, 7, 19, 38]
.Średnia stawka wygranej z i-tej rundzie:
[449.4, 855.6, 1100.8, 1166.8, 1290.6, 1386.3, 1500.2, 1526.5, 1639.3, 3227.1]
.
Tablica wyników
Bot count: 33
hard_coded Score: 16141 Total: 20075170
eenie_meanie_more Score: 15633 Total: 18513346
minus_one Score: 15288 Total: 19862540
AverageMine Score: 15287 Total: 19389331
heurist Score: 15270 Total: 19442892
blacklist_mod Score: 15199 Total: 19572326
Swapper Score: 15155 Total: 19730832
Almost_All_In Score: 15001 Total: 19731428
HighHorse Score: 14976 Total: 19740760
bid_higher Score: 14950 Total: 18545549
Graylist Score: 14936 Total: 17823051
above_average Score: 14936 Total: 19712477
below_average Score: 14813 Total: 19819816
Wingman_1 Score: 14456 Total: 18480040
wingman_2 Score: 14047 Total: 18482699
simple_bot Score: 13855 Total: 20935527
I_Dont_Even Score: 13505 Total: 20062500
AntiMaxer Score: 13260 Total: 16528523
Showoff Score: 13208 Total: 20941233
average_joe Score: 13066 Total: 18712157
BeatTheWinner Score: 12991 Total: 15859037
escalating Score: 12914 Total: 18832696
one_upper Score: 12618 Total: 18613875
half_in Score: 12605 Total: 19592760
distributer Score: 12581 Total: 18680641
copycat_or_sad Score: 11573 Total: 19026290
slow_starter Score: 11132 Total: 20458100
meanie Score: 10559 Total: 12185779
FiveFiveFive Score: 7110 Total: 24144915
patient_bot Score: 7088 Total: 22967773
forgetful_bot Score: 2943 Total: 1471500
bob_hater Score: 650 Total: 1300
one_dollar_bob Score: 401 Total: 401
W tej grze będziemy symulować aukcję z licytacją zamkniętą.
Każda aukcja jest grą dla 4 graczy i składa się z 10 rund. Początkowo gracze nie mają pieniędzy. Na początku każdej rundy każdy gracz otrzyma 500 USD, a następnie złoży własne oferty. Licytacja może być dowolną nieujemną liczbą całkowitą mniejszą lub równą niż mają. Zwykle ten, kto licytuje najwięcej, wygrywa rundę. Jednak, aby uczynić rzeczy bardziej interesującymi, jeśli kilku graczy licytuje tę samą cenę, ich oferta nie zostanie uwzględniona (a zatem nie może wygrać rundy). Na przykład, jeśli czterech graczy licytuje 400 400 300 200, jeden licytuje 300 wygrywa; jeśli licytują 400 400 300 300, nikt nie wygrywa. Zwycięzca powinien zapłacić za licytację.
Ponieważ jest to aukcja „sealed-bid”, jedyną informacją, którą gracz będzie wiedział o licytacji, jest zwycięzca i ile zapłacili, gdy rozpocznie się kolejna runda (aby gracz mógł wiedzieć, ile wszyscy mają).
Punktacja
Jedna aukcja odbędzie się dla każdej możliwej kombinacji dla 4 graczy. Oznacza to, że jeśli w sumie będzie N botów, odbędzie się aukcja N C 4 . Bot, który wygra najwięcej rund, zostanie zwycięzcą końcowym. W przypadku remisu wygrywa bot, który zapłacił najmniej w sumie. Jeśli nadal jest remis, w taki sam sposób jak licytacja, te remisy zostaną usunięte.
Kodowanie
Powinieneś zaimplementować klasę Python 3 z funkcją członka play_round
(i / __init__
lub innymi, jeśli potrzebujesz). play_round
powinien wziąć 3 argumenty (w tym siebie). Drugi i trzeci argument będą w kolejności: identyfikator zwycięzcy poprzedniej rundy, a następnie, ile zapłacili. Jeśli nikt nie wygra lub jest to pierwsza runda, obie będą miały -1. Twój identyfikator będzie zawsze wynosił 0, a identyfikatorami 1-3 będą inni gracze w kolejności określonej tylko przez pozycję na tym poście.
Dodatkowe zasady
1. Deterministyczny:
zachowanie twojej funkcji powinno zależeć tylko od argumentów wejściowych w aukcji. Oznacza to, że nie możesz uzyskać dostępu do plików, czasu, zmiennych globalnych ani niczego, co przechowa stany między różnymi aukcjami lub botami . Jeśli chcesz użyć generatora pseudolosowego, lepiej jest napisać go samemu (aby nie wpływać na programy innych osób, takie jak random
w Python lib) i upewnić się, że został zresetowany ze stałym ziarnem w __init__
pierwszej rundzie.
2. Trzy boty na osobę: Możesz przesłać maksymalnie 3 boty, abyś mógł opracować strategię, dzięki której boty będą „współpracować” w jakiś sposób.
3. Not Too Slow: Ponieważ będzie wiele aukcji, upewnij się, że boty nie będą działać zbyt wolno. Twoje boty powinny być w stanie ukończyć co najmniej 1000 aukcji w ciągu sekundy.
Kontroler
Oto kontroler, którego używam. Wszystkie boty zostaną zaimportowane i dodane do bot_list
zamówienia w tym poście.
# from some_bots import some_bots
bot_list = [
#one_bot, another_bot,
]
import hashlib
def decide_order(ls):
hash = int(hashlib.sha1(str(ls).encode()).hexdigest(), 16) % 24
nls = []
for i in range(4, 0, -1):
nls.append(ls[hash % i])
del ls[hash % i]
hash //= i
return nls
N = len(bot_list)
score = [0] * N
total = [0] * N
def auction(ls):
global score, total
pl = decide_order(sorted(ls))
bots = [bot_list[i]() for i in pl]
dollar = [0] * 4
prev_win, prev_bid = -1, -1
for rounds in range(10):
bids = []
for i in range(4): dollar[i] += 500
for i in range(4):
tmp_win = prev_win
if prev_win == i: tmp_win = 0
elif prev_win != -1 and prev_win < i: tmp_win += 1
bid = int(bots[i].play_round(tmp_win, prev_bid))
if bid < 0 or bid > dollar[i]: raise ValueError(pl[i])
bids.append((bid, i))
bids.sort(reverse = True)
winner = 0
if bids[0][0] == bids[1][0]:
if bids[2][0] == bids[3][0]: winner = -1
elif bids[1][0] == bids[2][0]: winner = 3
else: winner = 2
if winner == -1:
prev_win, prev_bid = -1, -1
else:
prev_bid, prev_win = bids[winner]
score[pl[prev_win]] += 1
total[pl[prev_win]] += prev_bid
dollar[prev_win] -= prev_bid
for a in range(N - 3):
for b in range(a + 1, N - 2):
for c in range(b + 1, N - 1):
for d in range(c + 1, N): auction([a, b, c, d])
res = sorted(map(list, zip(score, total, bot_list)), key = lambda k: (-k[0], k[1]))
class TIE_REMOVED: pass
for i in range(N - 1):
if (res[i][0], res[i][1]) == (res[i + 1][0], res[i + 1][1]):
res[i][2] = res[i + 1][2] = TIE_REMOVED
for sc, t, tp in res:
print('%-20s Score: %-6d Total: %d' % (tp.__name__, sc, t))
Przykłady
Jeśli potrzebujesz generatora pseudolosowego, tutaj jest prosty.
class myrand:
def __init__(self, seed): self.val = seed
def randint(self, a, b):
self.val = (self.val * 6364136223846793005 + 1) % (1 << 64)
return (self.val >> 32) % (b - a + 1) + a
class zero_bot:
def play_round(self, i_dont, care): return 0
class all_in_bot:
def __init__(self): self.dollar = 0
def play_round(self, winner, win_amount):
self.dollar += 500
if winner == 0: self.dollar -= win_amount
return self.dollar
class random_bot:
def __init__(self):
self.dollar = 0
self.random = myrand(1)
def play_round(self, winner, win_amount):
self.dollar += 500
if winner == 0: self.dollar -= win_amount
return self.random.randint(0, self.dollar)
class average_bot:
def __init__(self):
self.dollar = 0
self.round = 11
def play_round(self, winner, win_amount):
self.dollar += 500
self.round -= 1
if winner == 0: self.dollar -= win_amount
return self.dollar / self.round
class fortytwo_bot:
def play_round(self, i_dont, care): return 42
Wynik
all_in_bot Score: 20 Total: 15500
random_bot Score: 15 Total: 14264
average_bot Score: 15 Total: 20000
TIE_REMOVED Score: 0 Total: 0
TIE_REMOVED Score: 0 Total: 0
Zwycięzcą jest all_in_bot
. Pamiętaj, że zero_bot
i fortytwo_bot
mają ten sam wynik i sumę, więc są usuwane.
Te boty nie zostaną uwzględnione w konkursie. Możesz ich użyć, jeśli uważasz, że są świetne.
Konkurs finałowy odbędzie się o godzinie 23.11.2017 (UTC) . Wcześniej możesz wprowadzić zmiany w botach.
źródło
Odpowiedzi:
mocno zakodowane
Bot ten jest wynikiem treningu genetycznego przeciwko wielu innym pseudolosowym botom (i niektórym botom w innych odpowiedziach). Spędziłem trochę czasu na dopracowaniu, ale jego struktura jest w rzeczywistości bardzo prosta.
Decyzje opierają się tylko na ustalonym zestawie parametrów, a nie na wynikach poprzednich rund.
Kluczem wydaje się być pierwsza runda: musisz wejść za wszystko, licytacja 500 to bezpieczny ruch. Zbyt wiele botów próbuje przechytrzyć początkowy ruch, licytując 499 lub 498. Wygranie pierwszej rundy daje dużą przewagę przez resztę aukcji. Masz tylko 500 dolarów za sobą i masz czas na odzyskanie sił.
Bezpieczny zakład w drugiej rundzie to nieco ponad 990, ale nawet licytacja 0 daje dobry wynik. Zbyt wysokie licytowanie i wygrana może być gorsza niż przegrana w tej rundzie.
W trzeciej rundzie większość botów przestaje eskalować: 50% z nich ma teraz mniej niż 1500 dolarów, więc nie ma potrzeby marnowania pieniędzy w tej rundzie, 1170 to dobry kompromis. To samo w czwartej rundzie. Jeśli przegrałeś pierwsze trzy, możesz wygrać ten bardzo tanio i nadal mieć wystarczająco dużo pieniędzy na następny.
Następnie średnie pieniądze potrzebne do wygrania rundy wynoszą 1500 dolarów (co jest logicznym wnioskiem: wszyscy wygrywają rundę z czterech do tej pory, licytując mniej, aby wygrać później, po prostu marnuje się pieniądze, sytuacja się ustabilizowała i jest po prostu runda- robin od teraz).
Ostatnia runda musi być all-in, a pozostałe parametry są dopracowane, aby wygrać ostatnią rundę, licytując do tego czasu możliwie najniższą stawkę.
Wiele botów próbuje wygrać dziewiątą rundę, licytując ponad 2000 dolarów, więc wziąłem to pod uwagę i starałem się je przelicytować (i tak nie mogę wygrać dwóch ostatnich rund, a ostatnia będzie trudniejsza).
źródło
Powyżej średniej
Oferty powyżej średniej kwoty, jaką mają inni gracze. Licytuje wszystko w ostatniej rundzie.
źródło
Ja nawet nie
Uczestniczy tylko w rundach nieparzystych i ostatniej rundzie.
źródło
Zapominający bot nie wie, ile ma pieniędzy, więc po prostu wkłada pieniądze, które otrzymał w tej rundzie. Jeśli okaże się, że ma na końcu trochę pieniędzy, przekazuje je na cele charytatywne.
źródło
Jedna górna
Nie wiem dużo o Pythonie, więc mogę popełnić jakiś błąd
licytuje o 1 wyżej niż poprzednia zwycięska oferta lub wchodzi all-in w ostatniej rundzie.
Mogę w przyszłości zdecydować się na inną strategię, kiedy
win_amount
jest -1źródło
Bot pacjenta
Licytuje nic przez pierwsze pięć rund, następnie licytuje ~ 1000 dolarów na kolejne cztery rundy, a na koniec licytuje wszystko, co ma w ostatniej rundzie.
źródło
Naśladowca lub smutny
Trzeci i ostatni bot.
Ten bot licytuje dokładnie taką samą kwotę jak poprzedni zwycięzca (włączając siebie). Jednakże, jeśli nie będzie miał wystarczającej ilości gotówki, będzie to smutne i zamiast tego wystawi marny banknot 1 dolara ze swoją łzą. W ostatniej rundzie wszystko wejdzie.
Nigdy nie programuję w Pythonie, więc jeśli zobaczysz jakieś błędy, daj mi znać ...
źródło
-1
na pierwszej aukcji.Testowe uruchomienie
Zredagowałem poprzedni test przeprowadzony przez Steadybox, dodając najnowsze zgłoszenia.
Zamieszczam go tutaj, więc jest miejsce, w którym link może być aktualizowany nowszymi wersjami, ten post jest wiki społeczności, więc możesz go zaktualizować, jeśli opublikujesz nowe zgłoszenie, zmodyfikujesz stary lub po prostu coś zobaczysz nowy z innych zgłoszeń!
Oto link do uruchomienia testowego! (TIO)
źródło
Half In
Ten bot zawsze licytuje połowę tego, co mu pozostało, z wyjątkiem końcowej rundy, w której wszystko trafi.
Nigdy nie programuję w Pythonie, więc jeśli zobaczysz jakieś błędy, daj mi znać ...
źródło
Graylist
Zainspirowany przedłożeniem czarnej listy przez histocrata , ten bot przechowuje w pamięci wszystkie poprzednie zwycięskie zakłady innych graczy jako zarówno stosunek pieniędzy, które postawili w porównaniu do ich pełnych pieniędzy, jak i różnica między ich kwotą zakładu a pełną kwotą. Aby uniknąć przegrania remisu (co najwyraźniej jest tak naprawdę ważnym czynnikiem w tej konkurencji), unika się obstawiania dowolnej liczby, która mogłaby dać takie same wyniki, biorąc pod uwagę obecne środki przeciwników.
EDYCJA: jako wartość początkowa licytacji wykorzystuje teraz minimum: bieżące pieniądze, 1 więcej niż pieniądze najbogatszego przeciwnika, X więcej niż ostatni wygrany zakład lub Y więcej niż średnia wartość pieniędzy jego przeciwników. X i Y są stałymi, które prawdopodobnie zostaną zmodyfikowane przed końcem zawodów.
źródło
AverageMine
Ten gracz oblicza procent (licytację / sumę pieniędzy) zwycięzcy każdej rundy i licytuje swoje (suma pieniędzy * średni procent wygranych + 85), chyba że ma więcej pieniędzy niż wszyscy inni gracze, a następnie licytuje o 1 więcej niż najwyższy konkurent . Zaczyna się od stawki 99,0% kwoty początkowej.
źródło
Eenie Meanie More
Ten gracz jest identyczny z Meanie, z wyjątkiem jednej zmiennej. Ta wersja licytuje bardziej agresywnie i powoduje, że niektórzy gracze wydają więcej, niż według mnie, aukcja jest warta.
źródło
Dystrybutor
Kiedy ten bot przegrywa rundę, rozdziela nadwyżkę gotówki między wszystkie kolejne rundy. W pierwszej rundzie wkłada 499 $, myśląc, że pozostali remisują z 500 $ i zostaną wyeliminowani.
źródło
rounds
zamiastself.rounds
spowoduje błędy. To samo zmoney
.Meanie
Ten gracz bierze całkowitą gotówkę, która zostanie wprowadzona do gry, aby uzyskać średnią stawkę dla liczby graczy i pozostałych rund. Jeśli ten cel jest większy niż wszyscy inni gracze obecnie go trzymają, obniża swoją ofertę do salda swojego największego konkurenta plus jeden. Jeśli gracz nie może sobie pozwolić na swój cel, jest on all-in.
źródło
Pokonaj zwycięzcę
Licytuj o 1 więcej niż gracz z największą liczbą wygranych do tej pory
źródło
m,w
we właściwej kolejności?Minus jeden
źródło
Licytuj wyżej
Wciąż uczę się pytona; licytuj nieco wyżej niż ostatni zwycięzca.
źródło
inc = 100
nainc = 101
.FiveFiveFive
Pomija pierwszą rundę i licytuje 555 USD w pozostałych rundach. W ostatniej rundzie wejdzie all-in, chyba że 2 inne boty mają taką samą ilość (i prawdopodobnie będą remisować).
źródło
Prawie wszystko
Zawsze licytuje nieco mniej niż ma.
źródło
Eskalacja szybko
Licytuje zwiększając ułamki swoich pieniędzy w każdej rundzie (daj mi znać, jeśli jakieś błędy, jakiś czas odkąd użyłem Pythona)
źródło
Poniżej średniej
Podobnie jak powyżej średniej, ale idzie nieco niżej
źródło
Wysoki koń
Ten gracz licytuje wszystkie swoje pieniądze minus aktualny numer rundy, z wyjątkiem ostatniej rundy, w której bierze udział.
źródło
Swapper
Na przemian licytowanie jednego poniżej jego maksimum i wchodzenie all-in.
Uznałem, że muszę znaleźć coś, co mogłoby pokonać minus_one Steadyboksa. :)
źródło
Modułowa czarna lista
Obstawia najwyższą możliwą kwotę, która nie jest zgodna modulo 500 z dowolnymi liczbami, które wcześniej widział.
Edytowane, aby nie stosować czarnej listy, gdy może uzyskać gwarantowaną wygraną.
źródło
blacklist_mod
zajmuje piąte miejsce w tabeli liderów , ablacklist
na drugim miejscu. Jeśliblacklist
zamiast tego zostanie użyta starsza wersja ,blacklist
spadnie na szóste miejsce, aleblacklist_mod
obejmuje prowadzenie !blacklist
wyrzucenie wydaje się dawaćblacklist_mod
jeszcze bardziej solidny ołów , ale to nie jest jednoznaczne.Heurysta
Heurist traktuje tę grę jako jeden powtarzalny prawdopodobieństwa, więc wie, gdzie narysować linię.
Jest również skąpy, więc licytuje absolutne minimum wymagane do wygranej, kiedy to możliwe.
Oświadczenie:
max_bid
może ulec zmianieźródło
bob_hater
Ten bot nie lubi Boba, dlatego zawsze będzie licytować 2 $, aby wygrać z Bobem.
źródło
Pokazać
To ten facet, który popisuje się matematyką w sytuacjach, które naprawdę nie wymagają niczego tak skomplikowanego. Aż do ostatniej rundy (w której wchodzi all-in), używa modelu logistycznego, aby określić swoją ofertę, zwłaszcza jeśli jego wrogowie mają większą część swoich pieniędzy.
Zastosowana krzywa logistyczna to f (x) = 1 / (1 + e -8 (x-0,5) ), gdzie x jest stosunkiem bieżących pieniędzy wroga do całkowitej potencjalnej ceny pieniądza wroga. Im więcej mają inni, tym więcej licytuje. Daje to możliwą korzyść polegającą na licytowaniu prawie, ale nie całkiem, 500 USD w pierwszej rundzie.
źródło
AntiMaxer
Dopasuj najwyższą możliwą kwotę ze wszystkich pieniędzy gracza. Spowoduje, że każdy bot wchodzący za wszystko w tej rundzie się rozstrzygnie.
źródło
Prosty bot
Prawie to samo co Bot pacjenta, ale nie jako pacjent. Daje jednak znacznie lepszy wynik.
źródło
Wingman 2
Jeśli jeden skrzydłowy jest dobry, dwóch musi być lepszych?
źródło