Aukcja z pierwszą ofertą z ceną zamkniętą

32

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 AverageMinei heuristzamieni 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_roundpowinien 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 randomw 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_listzamó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_boti fortytwo_botmają 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.

Colera Su
źródło
5
Czy dostają 500 dolarów w każdej rundzie, czy w każdej aukcji (która trwa 10 rund)?
Stewie Griffin
1
Konkurs @KamilDrakari zostanie wznowiony po usunięciu szkodliwego bota z listy.
Colera Su
4
@Shufflepants To prawda, ale zawsze tak jest w przypadku wyzwań KotH. W przeszłości niektórzy ludzie robili bota pod koniec, aby przeciwdziałać wszystkim botom do tego momentu. Ale to tylko część wyzwania w stylu KotH. I sposób, w jaki działa większość wyzwań KotH, w tym ten jeden, przewaga nie będzie tak wielka. Możesz przeciwdziałać tylko tak wielu botom jednocześnie. Ładne pierwsze wyzwanie, Colera Su , i witamy w PPCG! Czekamy na wyniki. :)
Kevin Cruijssen
4
Oto test na TIO ze wszystkimi obecnymi botami.
Steadybox
2
W tej chwili jest to trudny wyścig ...
Zaid

Odpowiedzi:

13

mocno zakodowane

class hard_coded:
  def __init__(self):
    self.money = 0
    self.round = 0

  def play_round(self, did_i_win, amount):
    self.money += 500
    self.round += 1
    if did_i_win == 0:
      self.money -= amount
    prob = [500, 992, 1170, 1181, 1499, 1276, 1290, 1401, 2166, 5000][self.round - 1]
    if prob > self.money:
      return self.money
    else:
      return prob    

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).

GB
źródło
1
To jeden ze sposobów na wygraną. Gratulacje!
Luca H,
Muszę jednak przyznać, że bardziej podoba mi się inne zgłoszenie, ponieważ pojawiła się inna myśl. Nie sprawdzam, jak wygrywam z tymi innymi botami, ale co może być dobrą taktyką przeciwko każdemu losowemu botowi.
Luca H,
Rozumiem, podobały mi się (i głosowałem) niektóre inne zgłoszenia, ale jest to problem w skończonej domenie, a wiele zgłoszeń jest po prostu zbyt skomplikowanych. Istotą problemu jest generowanie sekwencji 10 liczb, więc zdecydowałem się zoptymalizować pod kątem konkretnej domeny, zamiast znaleźć ogólną procedurę. Jestem inżynierem, a nie matematykiem.
GB
2
@LucaH pozorna prostota podejścia zaprzecza nakładowi pracy wymaganemu do uzyskania tego konkretnego zestawu liczb. Próbowałem czegoś podobnego z moim własnym botem ze statystycznego punktu widzenia, i nie było to łatwe
Zaid
1
@Zaid oczywiście wymaga dużo pracy, ale brutalne zmuszanie jest po prostu ... brutalne;)
Luca H
12

Powyżej średniej

Oferty powyżej średniej kwoty, jaką mają inni gracze. Licytuje wszystko w ostatniej rundzie.

class above_average:
  def __init__(self):
    self.round = 0
    self.player_money = [0] * 4
  def play_round(self, winner, winning_bid):
    self.round += 1
    self.player_money = [x+500 for x in self.player_money]
    if winner != -1:
      self.player_money[winner] -= winning_bid
    if self.round == 10:
      return self.player_money[0]
    bid = sum(self.player_money[1:]) / 3 + 1
    if bid > self.player_money[0]:
      return self.player_money[0]
    return min(self.player_money[0], bid)
Okx
źródło
12

Ja nawet nie

class I_Dont_Even:
	def __init__(self):
		self.money = 0
		self.round = 0
	def play_round(self, loser, bid):
		self.money += 500 - (not loser) * bid
		self.round += 1
		return self.money * (self.round & 1 or self.round == 10)

Uczestniczy tylko w rundach nieparzystych i ostatniej rundzie.

Dennis
źródło
7

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.

class forgetful_bot:
  def play_round(self, winner, amt):
    return 500
RamenChef
źródło
15
Nie jestem zwycięzcą, ale może dlatego, że nie włożyłeś żadnego wysiłku w swojego bota
Mischa,
9
To jedna z pierwszych odpowiedzi. Coś jest potrzebne, aby piłka się potoczyła.
Khuldraeseth na'Barya
Nie głosowałem negatywnie, ale może dlatego, że chociaż coś potrzebowało, aby piłka się potoczyła, może zrobić coś bardziej interesującego? Zwłaszcza, że ​​jest to praktycznie identyczne z One Dollar Bob, który został użyty, aby go trochę rozpocząć
HyperNeutrino
7

Jedna górna

Nie wiem dużo o Pythonie, więc mogę popełnić jakiś błąd

class one_upper:
    def __init__(self): 
        self.money = 0
        self.round = 0
    def play_round(self, winner, win_amount):
        self.money += 500
        if winner == 0: self.money -= win_amount
        self.round += 1
        bid = win_amount + 1
        if self.money < bid or self.round == 10:
            bid = self.money
        return bid

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_amountjest -1

Kamil Drakari
źródło
7

Bot pacjenta

class patient_bot:
    def __init__(self):
        self.round = 0
        self.money = 0
    def rand(self, seed, max):
        return (394587485 - self.money*self.round*seed) % (max + 1)
    def play_round(self, winner, amount):
        self.round += 1
        self.money += 500
        if winner == 0:
            self.money -= amount
        if self.round < 6:
            return 0
        else:
            bid = 980 + self.rand(amount, 35)
            if self.money < bid or self.round == 10:
                bid = self.money
            return bid

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.

Steadybox
źródło
7

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.

class copycat_or_sad:
  def __init__(self):
    self.money = 0
    self.round = -1
  def play_round(self, winner, win_amount):
    # Default actions:
    #  Collect 500 dollars
    self.money += 500
    #  If it was the winner: subtract the win_amount from his money
    if winner == 0:
      self.money -= win_amount
    #  One round further
    self.round += 1

    # If it's the final round: bid all-in
    if self.round == 9:
      return self.money
    # Else-if there was no previous winner, or it doesn't have enough money left: bid 1
    if win_amount < 1 or self.money < win_amount:
      return 1
    # Else: bid the exact same as the previous winner
    return win_amount

Nigdy nie programuję w Pythonie, więc jeśli zobaczysz jakieś błędy, daj mi znać ...

Kevin Cruijssen
źródło
2
To oferty -1na pierwszej aukcji.
Okx,
7

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)

Leo
źródło
czy powinienem być przygnębiony, że mój bot, który miał być destrukcyjny, pokonuje moje dwa „prawdziwe” zgłoszenia?
thegreatemu
@thegreatemu Ciekawe jest, jak boty wchodzą w interakcje ze sobą. Jeden nowy bot może radykalnie zmienić ranking. Coś interesującego, co znalazłem, to to, że jeśli uczestniczy bot z czarnej listy usuniętej przez histocrata, moje dwa boty przechodzą na szczyt rankingu. :)
Jo.
6

Half In

Ten bot zawsze licytuje połowę tego, co mu pozostało, z wyjątkiem końcowej rundy, w której wszystko trafi.

class half_in:
  def __init__(self):
    self.money = 0
    self.round = -1
  def play_round(self, winner, win_amount):
    # Default actions:
    #  Collect 500 dollars
    self.money += 500
    #  If it was the winner: subtract the win_amount from his money
    if winner == 0:
      self.money -= win_amount
    #  One round further
    self.round += 1

    # If it's the final round: bid all in
    if self.round == 9:
      return self.money
    # Else: Bid half what it has left:
    return self.money / 2

Nigdy nie programuję w Pythonie, więc jeśli zobaczysz jakieś błędy, daj mi znać ...

Kevin Cruijssen
źródło
6

Graylist

class Graylist:
  def __init__(self):
    self.round = 0
    self.player_money = [0] * 4
    self.ratios = {1}
    self.diffs = {0}
  def play_round(self, winner, winning_bid):
    self.round += 1
    if winner != -1:
      if winner >0 and winning_bid>0:
        self.ratios.add(self.player_money[winner]/winning_bid)
        self.diffs.add(self.player_money[winner]-winning_bid)
      self.player_money[winner] -= winning_bid
    self.player_money = [x+500 for x in self.player_money]
    tentative_bid = min(self.player_money[0],max(self.player_money[1:])+1, winning_bid+169, sum(self.player_money[1:])//3+169)
    while tentative_bid and (tentative_bid in (round(m*r) for m in self.player_money[1:] for r in self.ratios)) or (tentative_bid in (m-d for m in self.player_money[1:] for d in self.diffs)):
      tentative_bid = tentative_bid - 1
    return tentative_bid

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.

Lew
źródło
6

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.

class AverageMine:
    nplayers = 4
    maxrounds = 10
    def __init__(self):
        self.money = [0] * self.nplayers
        self.wins = [0] * self.nplayers
        self.round = 0
        self.average = 0
    def play_round(self, winner, win_amt):
        self.round += 1
        for i in range(self.nplayers):
            if i == winner:
                self.average = (self.average * (self.round - 2) + (win_amt / self.money[i])) / (self.round - 1)
                self.money[i] -= win_amt
                self.wins[i] += 1
            self.money[i] += 500
        if self.round == 1:
            return int(0.990 * self.money[0])
        elif self.round < self.maxrounds:
            if self.money[0] > self.money[1] + 1 and self.money[0] > self.money[2] + 1 and self.money[0] > self.money[3] + 1:
                return max(self.money[1],self.money[2],self.money[3]) + 1
            bid = int(self.average * self.money[0]) + 85
            return min(self.money[0],bid)
        else:
            bid = self.money[0]
            return bid
Jo.
źródło
6

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.

class eenie_meanie_more:
    def __init__(self):
        self.money = [0] * 4
        self.rounds = 11
        self.total_spent = 0

    def play_round(self, winner, winning_bid):
        self.money = [x+500 for x in self.money]
        self.rounds -= 1
        if winner != -1:
            self.money[winner] -= winning_bid
            self.total_spent += winning_bid
        bid = 500
        if self.rounds > 0 and self.total_spent < 20000:
            bid = int((20000 - self.total_spent)/self.rounds/4)+440
        return min(bid, max(self.money[1:])+1, self.money[0])
nie
źródło
5

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.

class distributer:
  def __init__(self):
    self.money = 0
    self.rounds = 11
  def play_round(self, winner, amt):
    self.money += 500
    self.rounds -= 1
    if self.rounds == 10:
      return 499
    if winner == 0:
      self.money -= amt
    return ((self.rounds - 1) * 500 + self.money) / self.rounds
RamenChef
źródło
1
Używanie roundszamiast self.roundsspowoduje błędy. To samo z money.
Jeremy Weirich,
5

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.

class meanie:
    def __init__(self):
        self.money = [0] * 4
        self.rounds = 11
        self.total_spent = 0

    def play_round(self,winner,winning_bid):
        self.money = [x+500 for x in self.money]
        self.rounds -= 1
        if winner != -1:
            self.money[winner] -= winning_bid
            self.total_spent += winning_bid
        bid = 500
        if self.rounds > 0 and self.total_spent < 20000:
            bid = int((20000 - self.total_spent)/self.rounds/4)+1
        return min(bid,max(self.money[1:])+1,self.money[0])
nie
źródło
5

Pokonaj zwycięzcę

Licytuj o 1 więcej niż gracz z największą liczbą wygranych do tej pory

class BeatTheWinner:
    nplayers = 4
    maxrounds = 10
    def __init__(self):
        self.money = [0] * self.nplayers
        self.wins = [0] * self.nplayers
        self.round = 0

    def play_round(self, winner, win_amt):
        self.round += 1
        for i in range(self.nplayers):
            self.money[i] += 500
            if i == winner:
                self.money[i] -= win_amt
                self.wins[i] += 1
        mymoney = self.money[0]
        for w,m in sorted(zip(self.wins, self.money),reverse=True):
            if mymoney > m:
                return m+1
        #if we get here we can't afford our default strategy, so
        return int(mymoney/10)
thegreatemu
źródło
4
Czy jesteś m,wwe właściwej kolejności?
Jo.
5

Minus jeden

class minus_one:
    def __init__(self):
        self.money = 0
    def play_round(self, winner, amount):
        self.money += 500
        if winner == 0:
            self.money -= amount
        return self.money - 1
Steadybox
źródło
5

Licytuj wyżej

class bid_higher:
    def __init__(self):
        self.dollar = 0
        self.round = 0
    def play_round(self, winner, win_amount):
        self.dollar += 500
        self.round += 1
        inc = 131
        if winner == 0: self.dollar -= win_amount
        if self.round == 10: return self.dollar
        if win_amount == 0: win_amount = 500
        if self.dollar > (win_amount + inc):
            return win_amount + inc
        else:
            if self.dollar > 1:
                return self.dollar -1
            else:
                return 0

Wciąż uczę się pytona; licytuj nieco wyżej niż ostatni zwycięzca.

rancid_banana
źródło
Witamy w PPCG! Wygląda na to, że twój bot uzyska jeszcze lepszy wynik, jeśli zmienisz inc = 100na inc = 101.
Steadybox
Naprawdę działam wbrew własnym interesom, ale możesz łatwo poprawić swój wynik, śledząc zakręty i wchodząc all-in w ostatniej rundzie;)
Leo
Dzięki za sugestie; Dodałem ostatnią rundę all-in, dostroiłem przyrost i dodałem kilka botów skrzydłowych, aby dać temu botowi impuls.
rancid_banana
Cześć, mam nadzieję, że nie masz nic przeciwko, ale przygotowywałem testbench z całym bieżącym zgłoszeniem i dowiedziałem się, że twój kod czasami zwraca nieprawidłowe wartości w ostatniej rundzie, więc naprawiłem błąd przez przestawienie zamów kilka wierszy. Przepraszam, jeśli zmieniłem coś, czego nie chciałbyś, przywróć zmiany i napraw błąd w inny sposób!
Lew
@Leo: Nie ma problemu, dziękuję za zainteresowanie ..
rancid_banana
4

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ć).

class FiveFiveFive:
    nplayers = 4
    maxrounds = 10
    def __init__(self):
        self.money = [0] * self.nplayers
        self.wins = [0] * self.nplayers
        self.round = 0

    def play_round(self, winner, win_amt):
        self.round += 1
        for i in range(self.nplayers):
            self.money[i] += 500
            if i == winner:
                self.money[i] -= win_amt
                self.wins[i] += 1
        if self.round == 1:
            return 0
        elif self.round < self.maxrounds:
            return min(555, self.money[0])
        else:
            bid = self.money[0]
            return bid if self.money.count(bid) < 3 else bid-1
thegreatemu
źródło
4

Prawie wszystko

class Almost_All_In:
	def __init__(self):
		self.money = 0
		self.round = 0
	def play_round(self, loser, bid):
		self.money += 500 - (not loser) * bid
		self.round += 1
		return self.money - self.round % 3 * 3 - 3

Zawsze licytuje nieco mniej niż ma.

Dennis
źródło
4

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)

class escalating:
  def __init__(self):
    self.money = 0
    self.round = 0
  def play_round(self, winner, win_amount):
    # Default actions:
    #  Collect 500 dollars
    self.money += 500
    #  If it was the winner: subtract the win_amount from his money
    if winner == 0:
      self.money -= win_amount
    #  One round further
    self.round += 1

    # bid round number in percent times remaining money, floored to integer
    return self.money * self.round // 10
Scott
źródło
4

Poniżej średniej

Podobnie jak powyżej średniej, ale idzie nieco niżej

class below_average:
  def __init__(self):
    self.round = 0
    self.player_money = [0] * 4
  def play_round(self, winner, winning_bid):
    self.round += 1
    self.player_money = [x+500 for x in self.player_money]
    if winner != -1:
      self.player_money[winner] -= winning_bid
    if self.round == 10:
      return self.player_money[0]
    bid = sum(self.player_money[1:]) / 3 - 2
    if bid > self.player_money[0]:
      return self.player_money[0]
    return min(self.player_money[0], bid)
Okx
źródło
4

Wysoki koń

Ten gracz licytuje wszystkie swoje pieniądze minus aktualny numer rundy, z wyjątkiem ostatniej rundy, w której bierze udział.

class HighHorse:
    maxrounds = 10
    def __init__(self):
        self.money = 0
        self.round = 0
    def play_round(self, winner, win_amt):
        self.round += 1
        if 0 == winner:
            self.money -= win_amt
        self.money += 500
        if self.round < self.maxrounds:
            return self.money - self.round
        else:
            bid = self.money
            return bid
Jo.
źródło
4

Swapper

Na przemian licytowanie jednego poniżej jego maksimum i wchodzenie all-in.

class Swapper:
    def __init__(self):
        self.money = 0
        self.round = 0
    def play_round(self, loser, bid):
        self.money += 500 - (not loser) * bid
        self.round += 1
        if self.round & 1:
            return self.money - 1
        return self.money

Uznałem, że muszę znaleźć coś, co mogłoby pokonać minus_one Steadyboksa. :)

Jo.
źródło
4

Modułowa czarna lista

class blacklist_mod:
  def __init__(self):
    self.round = 0
    self.player_money = [0] * 4
    self.blacklist = {0, 499}
  def play_round(self, winner, winning_bid):
    self.round += 1
    self.player_money = [x+500 for x in self.player_money]
    if winner != -1:
      self.player_money[winner] -= winning_bid
      self.blacklist.add(winning_bid % 500)
      self.blacklist |= {x % 500 for x in self.player_money[1:]}
    tentative_bid = self.player_money[0]
    autowin = max(self.player_money[1:])+1
    if tentative_bid < autowin:
      while tentative_bid and (tentative_bid % 500) in self.blacklist:
        tentative_bid = tentative_bid - 1
    else:
      tentative_bid = autowin
    self.blacklist.add(tentative_bid % 500)
    return tentative_bid

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ą.

histocrat
źródło
Co ciekawe, wydaje się, że najnowsza aktualizacja Twojego drugiego bota wpływa na tego bota negatywnie. Obecnie blacklist_modzajmuje piąte miejsce w tabeli liderów , a blacklistna drugim miejscu. Jeśli blacklistzamiast tego zostanie użyta starsza wersja , blacklistspadnie na szóste miejsce, ale blacklist_mod obejmuje prowadzenie !
Steadybox,
Całkowite blacklistwyrzucenie wydaje się dawać blacklist_modjeszcze bardziej solidny ołów , ale to nie jest jednoznaczne.
Steadybox
Och, dzięki, to ma sens - wcześnie zbliżają się do tego samego algorytmu bez starej logiki specjalnych przypadków, więc stąpają sobie po palcach. Myślę, że po prostu usunę oryginalnego bota; Nie mogę wymyślić żadnego dobrego powodu, żeby to utrzymać.
histocrat
4

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.

class heurist:
    def __init__(self):
        self.money = 0
        self.round = -1
        self.net_worth = [0] * 4
    def play_round(self, winner, bid):
        self.round += 1
        self.money += 500
        if winner == 0: self.money -= bid
        if winner != -1: self.net_worth[winner] -= bid
        self.net_worth = [x+500 for x in self.net_worth]
        max_bid = [498,1000,1223,1391,1250,1921,2511,1666,1600,5000][self.round]
        if self.money > max_bid:
            return 1 + min(max_bid,max(self.net_worth[1:3]))
        else:
            return self.money

Oświadczenie: max_bidmoże ulec zmianie

Zaid
źródło
4

bob_hater

Ten bot nie lubi Boba, dlatego zawsze będzie licytować 2 $, aby wygrać z Bobem.

class bob_hater:
    def play_round(bob,will,loose):
        return 2
Luca H.
źródło
4

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.

class Showoff:
  def __init__(self):
      self.moneys = [0, 0, 0]
      self.roundsLeft = 10
  def play_round(self, winner, winning_bid):
      import math
      self.moneys = [self.moneys[0] + 500,
                     self.moneys[1] + 1500,
                     self.moneys[2] + 1500]
      self.roundsLeft -= 1
      if winner > 0:
          self.moneys[1] -= winning_bid
      if winner == 0:
          self.moneys[0] -= winning_bid
      if self.roundsLeft == 0:
          return self.moneys[0]
      ratio = self.moneys[1] / self.moneys[2]
      logisticized = (1 + (math.e ** (-8 * (ratio - 0.5)))) ** -1
      return math.floor(self.moneys[0] * logisticized)

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.

Khuldraeseth na'Barya
źródło
3

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.

class AntiMaxer:
    nplayers = 4
    maxrounds = 10
    def __init__(self):
        self.money = [0] * self.nplayers
        self.wins = [0] * self.nplayers
        self.round = 0

    def play_round(self, winner, win_amt):
        self.round += 1
        for i in range(self.nplayers):
            self.money[i] += 500
            if i == winner:
                self.money[i] -= win_amt
                self.wins[i] += 1
        return max((m for m in self.money[1:] if m<=self.money[0]),
                   default=0)    
thegreatemu
źródło
3

Prosty bot

class simple_bot:
    def __init__(self):
        self.round = 0
        self.money = 0
    def rand(self, seed, max):
        return (394587485 - self.money*self.round*seed) % (max + 1)
    def play_round(self, winner, amount):
        self.round += 1
        self.money += 500
        if winner == 0:
            self.money -= amount
        bid = 980 + self.rand(amount, 135)
        if self.money < bid or self.round == 10:
            bid = self.money
        return bid

Prawie to samo co Bot pacjenta, ale nie jako pacjent. Daje jednak znacznie lepszy wynik.

Steadybox
źródło
3

Wingman 2

Jeśli jeden skrzydłowy jest dobry, dwóch musi być lepszych?

class wingman_2:
    def __init__(self):
        self.dollar = 0
        self.round = 0
    def play_round(self, winner, win_amount):
        self.round += 1
        self.dollar += 500
        inc = 129
        if win_amount == 0: win_amount = 500
        if winner == 0: self.dollar -= win_amount
        if self.round == 10: return self.dollar
        if self.dollar > win_amount + inc:
            return win_amount + inc
        else:
            if self.dollar > 1: return self.dollar -1
            else:
                return 0
rancid_banana
źródło
Twój kod nie będzie działał, ponieważ potrzebujesz wcięcia dla rzeczy w klasie
HyperNeutrino
Co ciekawe, obaj twoi skrzydłowi zdają się bić twojego oryginalnego bota (link do pastebina zawiera link TIO, który jest zbyt długi, aby opublikować komentarz, a nawet zbyt długi, aby skrócić adresy URL ...)
Steadybox
1
Odkryłem, że wyniki były bardzo wrażliwe na pulę innych botów; niewielkie zmiany wartości przyrostu wydają się mieć nieproporcjonalne wyniki.
rancid_banana