Asta di offerta sigillata al primo prezzo


32

Risultato finale

La competizione è finita. Congratulazioni a hard_coded!

Alcuni fatti interessanti:

  • In 31600 delle 40920 aste (77,2%), il vincitore del primo round ha vinto il maggior numero di round in quell'asta.

  • Se nella competizione vengono inclusi esempi di robot, i primi nove posti non cambieranno tranne quello AverageMinee heuristcambieranno le loro posizioni.

  • I 10 migliori risultati in un'asta:

[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
  • Conteggio Tie (numero di aste che l'i-esimo turno aveva nessun vincitore): [719, 126, 25, 36, 15, 58, 10, 7, 19, 38].

  • Offerta media vincente della i-esimo turno: [449.4, 855.6, 1100.8, 1166.8, 1290.6, 1386.3, 1500.2, 1526.5, 1639.3, 3227.1].

tabellone segnapunti

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

In questo gioco, simuleremo un'asta con offerta sigillata.

Ogni asta è un gioco a 4 giocatori, composto da 10 round. Inizialmente, i giocatori non hanno soldi. All'inizio di ogni round, ogni giocatore riceverà $ 500, quindi farà le proprie offerte. L'offerta può essere qualsiasi numero intero non negativo inferiore o uguale all'importo che hanno. Di solito, chi offre il punteggio più alto vince il round. Tuttavia, per rendere le cose più interessanti, se più giocatori dichiarano lo stesso prezzo, la loro offerta non verrà presa in considerazione (quindi non può vincere il round). Ad esempio, se quattro giocatori dichiarano 400 400 300 200, quello che offre 300 vince; se offrono 400 400 300 300, nessuno vince. Il vincitore dovrebbe pagare ciò che ha offerto.

Dato che si tratta di un'asta "a offerta chiusa", l'unica informazione che il giocatore saprà sull'offerta è il vincitore e quanto ha pagato all'inizio del prossimo round (così il giocatore può sapere quanto tutti hanno).


punteggio

Si terrà un'asta per ogni possibile combinazione di 4 giocatori. Cioè, se ci sono N robot in totale, ci sarà un'asta N C 4 . Il bot che vince il maggior numero di round sarà il vincitore finale. Nel caso in cui ci sia un pareggio, vincerà il bot che ha pagato il minimo. Se c'è ancora un pareggio, allo stesso modo dell'offerta, questi legami verranno rimossi.


Coding

Dovresti implementare una classe Python 3 con una funzione membro play_round(e __init__o altre se ne hai bisogno). play_rounddovrebbe prendere 3 argomenti (incluso self). Il secondo e il terzo argomento saranno, in ordine: l'id del vincitore del round precedente, seguito da quanto hanno pagato. Se nessuno vince o è il primo round, saranno entrambi -1. Il tuo ID sarà sempre 0 e l'id 1-3 saranno gli altri giocatori in un ordine determinato solo dalla posizione su questo post.


Regole aggiuntive

1. Deterministico: il comportamento della tua funzione dovrebbe dipendere solo dagli argomenti di input all'interno di un'asta. Cioè, non è possibile accedere a file, tempo, variabili globali o qualsiasi cosa che memorizzerà gli stati tra aste o robot diversi . Se vuoi usare un generatore pseudocasuale, è meglio scriverlo da solo (per evitare di influenzare i programmi di altri come randomin Python lib), e assicurarti di averlo resettato con un seed fisso nel __init__primo round.

2. Tre robot per persona: puoi inviare al massimo 3 robot, quindi puoi sviluppare una strategia per "cooperare" in qualche modo.

3. Non troppo lento: poiché ci saranno molte aste, assicurati che i tuoi robot non funzionino troppo lentamente. I tuoi robot dovrebbero essere in grado di completare almeno 1.000 aste in un secondo.


controllore

Ecco il controller che sto usando. Tutti i bot verranno importati e aggiunti bot_listnell'ordine in questo post.

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

Esempi

Se hai bisogno di un generatore pseudocasuale, eccone uno semplice.

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

Risultato

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

Il vincitore è all_in_bot. Si noti che zero_bote fortytwo_bothanno lo stesso punteggio e totale, quindi sono rimossi.

Questi robot non saranno inclusi nella competizione. Puoi usarli se pensi che siano fantastici.


La competizione finale si svolgerà il 23/11/2017 alle 14:00 (UTC) . Prima di allora puoi apportare qualsiasi modifica ai tuoi robot.


5
Ricevono 500 dollari per round o ogni asta (che dura 10 round)?
Stewie Griffin,

1
La competizione @KamilDrakari si riavvierà con il bot incriminato rimosso dalla lista.
Colera Su

4
@Shufflepants Vero, ma questo è sempre il caso delle sfide di KotH. In passato alcune persone hanno effettivamente creato un bot vicino alla fine per contrastare tutti i robot fino a quel momento. Ma è solo una parte della sfida in stile KotH. E il modo in cui funzionano la maggior parte delle sfide di KotH, incluso questo, il vantaggio non sarà eccezionale. Puoi contrastare così tanti robot contemporaneamente ... Bella prima sfida, Colera Su , e benvenuto in PPCG! In attesa di risultati. :)
Kevin Cruijssen,

4
Ecco un test eseguito su TIO con tutti i robot attuali.
Steadybox,

2
È una gara serrata al momento ...
Zaid,

Risposte:


13

hard_coded

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    

Questo bot è il risultato dell'allenamento genetico contro molti altri robot pseudo-casuali (e alcuni dei robot in altre risposte). Ho trascorso un po 'di tempo alla fine della messa a punto, ma la sua struttura è in realtà molto semplice.

Le decisioni si basano solo su una serie fissa di parametri e non sul risultato dei round precedenti.

La chiave sembra essere il primo round: devi andare all-in, offrendo 500 è la mossa sicura. Troppi robot stanno cercando di superare in astuzia la mossa iniziale offrendo 499 o 498. Vincere il primo round ti dà un grande vantaggio per il resto dell'asta. Ti mancano solo 500 dollari e hai tempo per riprenderti.

Una scommessa sicura nel secondo turno è di poco superiore a 990, ma anche l'offerta di 0 dà un buon risultato. Fare offerte troppo alte e vincere potrebbe essere peggio che perdere questo round.

Nel terzo round, la maggior parte dei robot smette di aumentare: il 50% di loro ha ormai meno di 1500 dollari, quindi non è necessario sprecare soldi in questo round, 1170 è un buon compromesso. Stessa cosa nel quarto round. Se hai perso i primi tre, puoi vincere questo molto a buon mercato e avere ancora abbastanza soldi per il prossimo.

Dopodiché, il denaro medio richiesto per vincere un round è di 1500 dollari (che è la logica conclusione: ormai tutti vincono un round su quattro, offrire meno per vincere in seguito significa solo sprecare soldi, la situazione si è stabilizzata ed è solo round- pettirosso d'ora in poi).

L'ultimo round deve essere all-in e gli altri parametri sono messi a punto per vincere l'ultimo round offrendo il più basso possibile fino ad allora.

Molti robot provano a vincere il nono round offrendo più di 2000 dollari, quindi ne ho tenuto conto e ho provato a superarli (non posso comunque vincere entrambi gli ultimi due round, e l'ultimo sarà più difficile).


1
Bene, questo è un modo per vincere. Congratulazioni!
Luca H,

Ma devo ammettere che mi piacciono di più le altre osservazioni, perché c'è stata un'altra forma di pensiero. Non provando come avrei vinto contro quegli altri robot, ma quale potrebbe essere una buona tattica contro qualsiasi bot casuale.
Luca H,

Posso capire, mi sono piaciute (e votate) alcune altre proposte, ma questo è un problema su un dominio finito, e molte domande sono semplicemente troppo complesse. Il nocciolo del problema sta generando una sequenza di 10 numeri, quindi ho scelto di ottimizzare per un dominio specifico invece di trovare una procedura generale. Sono un ingegnere, non un matematico.
GB

2
@LucaH l'apparente semplicità dell'approccio smentisce la quantità di lavoro richiesto per arrivare a questo particolare insieme di numeri. Stavo tentando una cosa simile con il mio bot da un punto di vista statistico, e non è stato facile
Zaid,

1
@Zaid ovviamente c'è molto lavoro da fare, ma la forza bruta è proprio così ... bruta;)
Luca H

12

Sopra la media

Offerte superiori alla quantità media di denaro degli altri giocatori. Offerte tutto nell'ultimo round.

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)

12

Io nemmeno

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)

Partecipa solo ai round dispari e all'ultimo round.


7

Il bot smemorato non sa quanti soldi ha, quindi mette solo i soldi che gli sono stati dati per questo round. Se scopre di avere dei soldi alla fine, li dona in beneficenza.

class forgetful_bot:
  def play_round(self, winner, amt):
    return 500

15
Non sono il downvoter, ma forse è perché non hai fatto alcuno sforzo nel tuo bot
Mischa,

9
Questa è una delle prime risposte. Qualcosa è necessario per far rotolare la palla.
Khuldraeseth na'Barya,

Non ho votato in negativo, ma forse è perché anche se qualcosa doveva far rotolare la palla, forse fare qualcosa di leggermente più interessante? Soprattutto perché questo è praticamente identico a One Dollar Bob che è stato usato per avviarlo in un
certo senso

7

Una tomaia

Non so molto di Python, quindi potrei commettere un errore

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

fa un'offerta 1 in più rispetto alla precedente offerta vincente o va all-in durante l'ultimo round.

In futuro potrei decidere una strategia diversa per quando win_amountè -1


7

Bot paziente

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

Non offre nulla per i primi cinque round, quindi offre ~ 1000 dollari per i successivi quattro round e infine offre tutto ciò che ha nell'ultimo round.


7

Copione o triste

Terzo e ultimo bot.
Questo bot offrirà esattamente lo stesso importo del vincitore precedente (incluso se stesso). Tuttavia, se non ha abbastanza denaro per farlo, sarà triste e offrirà invece una misera banconota da 1 dollaro con la sua lacrima su di essa. Nel round finale andrà all-in.

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

Non ho mai programmato in Python, quindi se vedi qualche errore fammi sapere ..


2
Questo fa offerte -1per la prima asta.
Okx,

7

Prova

Ho modificato una precedente esecuzione di test messa insieme da Steadybox aggiungendo le ultime novità.

Lo sto postando qui in modo che ci sia un posto dove il link può essere aggiornato con versioni più recenti, questo post è un wiki della comunità quindi sentiti libero di aggiornarlo se pubblichi un nuovo invio, ne modifichi uno vecchio o semplicemente vedi qualcosa nuovo da qualche altra presentazione!

Ecco il link per l'esecuzione del test! (OIT)


dovrei essere depresso che il mio bot che doveva essere dirompente batte le mie due "vere" osservazioni?
thegreatemu,

@thegreatemu È interessante vedere come i robot interagiscono tra loro. Un singolo nuovo bot potrebbe cambiare radicalmente le classifiche. Qualcosa di interessante che ho scoperto è che se il bot della lista nera cancellata dall'istocrate partecipa, i miei due robot si spostano in cima alla classifica. :)
Jo.

6

Half In

Questo bot offre sempre la metà di ciò che è rimasto, tranne nel round finale in cui andrà all in.

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

Non ho mai programmato in Python, quindi se vedi qualche errore fammi sapere ..


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

Ispirato alla presentazione nella lista nera dell'istocratico , questo bot mantiene in memoria tutte le precedenti scommesse vincenti di altri giocatori sia come rapporto tra il denaro scommesso rispetto al loro intero denaro sia la differenza tra l'importo della loro scommessa e l'intero importo. Al fine di evitare di perdere un pareggio (che a quanto pare in realtà è un grande fattore in questa competizione) evita quindi di scommettere qualsiasi numero che potrebbe dare gli stessi risultati dati i soldi attuali dei suoi avversari.

MODIFICA: poiché il valore iniziale dell'offerta ora utilizza il minimo tra: i suoi soldi correnti, 1 in più rispetto ai soldi dell'avversario più ricco, X in più rispetto all'ultima scommessa vincente o Y in più rispetto ai soldi medi dei suoi avversari. X e Y sono costanti che probabilmente verranno modificate prima della fine della competizione.


6

AverageMine

Questo giocatore calcola la percentuale (offerta / denaro totale) per il vincitore di ogni round e offre la sua (denaro totale * percentuale media di vincita + 85) a meno che non abbia più denaro di tutti gli altri giocatori, quindi offre 1 in più rispetto al concorrente più alto . Inizia con un'offerta del 99,0% dell'importo iniziale.

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

6

Eenie Meanie More

Questo giocatore è identico a Meanie, ad eccezione di una variabile. Questa versione fa offerte più aggressive e fa sì che alcuni giocatori spendano più di quanto crede che l'asta valga la pena.

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

5

distributore

Quando questo bot perde un round, distribuisce il denaro in eccesso tra tutti i round successivi. Mette $ 499 al primo turno pensando che gli altri vinceranno $ 500 e saranno eliminati.

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

1
L'uso al roundsposto di self.roundscausa errori. Lo stesso con money.
Jeremy Weirich,

5

meanie

Questo giocatore prende il denaro totale che entrerà in gioco per ottenere l'offerta media sul numero di giocatori e sui round rimanenti. Se questo obiettivo è più di tutti gli altri giocatori attualmente in possesso, riduce la sua offerta al saldo del suo più grande concorrente più uno. Se il giocatore non può permettersi il bersaglio, è 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])

5

Batti il ​​vincitore

Fai 1 in più rispetto al giocatore con il maggior numero di vittorie finora

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)

4
Sei m,wnell'ordine corretto?
Jo.

5

Meno uno

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

5

Fai un'offerta più alta

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

Sto ancora imparando il pitone; offerta un po 'più alta dell'ultimo vincitore.


Benvenuti in PPCG! Sembra che il tuo bot ottenga un punteggio ancora migliore se cambi inc = 100a inc = 101.
Steadybox,

Sto davvero andando contro i miei interessi qui, ma potresti facilmente migliorare il tuo punteggio tenendo traccia dei turni e andando all-in nel round finale;)
Leo

Grazie per i suggerimenti; Ho aggiunto un ultimo round all-in, messo a punto l'incremento e ho aggiunto un paio di bot di wingmen per dare una spinta a questo bot ..
rancid_banana

Ciao, spero che non ti dispiaccia, ma stavo mettendo insieme un banco di prova con tutta l'invio corrente e ho scoperto che il tuo codice a volte restituiva valori non validi nell'ultimo round, quindi ho risolto il bug riorganizzando l'ordine un paio di righe. Scusami se ho cambiato qualcosa che non avresti, sentiti libero di ripristinare le modifiche e correggere il bug in un altro modo!
Leone,

@Leo: nessun problema, grazie per l'interesse ..
rancid_banana,

4

FiveFiveFive

Salta il primo round e offre $ 555 sui round rimanenti. Nell'ultimo round, andrà all in a meno che altri 2 robot abbiano lo stesso importo (e presumibilmente pareggino).

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

4

Quasi tutti dentro

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

Fa sempre offerte leggermente inferiori rispetto a quanto ha fatto.


4

Escalating rapidamente

Offre quote crescenti dei suoi soldi ogni round (per favore fatemi sapere se ci sono errori, qualche tempo da quando ho usato Python)

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

4

Sotto la media

Simile alla media sopra, ma va un po 'più in basso

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)

4

HighHorse

Questo giocatore offre tutti i suoi soldi meno il numero del round corrente, tranne l'ultimo round, dove va all in.

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

4

swapper

Si alterna tra l'offerta di uno sotto il suo massimo e andare 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

Ho pensato di dover trovare qualcosa che potesse battere il meno_uno di Steadybox. :)


4

Lista nera modulare

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

Scommette la quantità più alta possibile che non è congruente modulo 500 a tutti i numeri che ha visto prima.

Modificato per non applicare la lista nera quando può ottenere una vittoria garantita.


Curiosamente, sembra che l'ultimo aggiornamento dell'altro bot stia influenzando negativamente questo bot. Attualmente, blacklist_modè quinto nella classifica , mentre blacklistè al secondo posto. Se blacklistinvece viene utilizzata la versione precedente di , blacklistscende al sesto posto, ma blacklist_mod prende il comando !
Steadybox

Eliminare del blacklisttutto sembra dare blacklist_modun vantaggio ancora più solido , ma questo è inconcludente.
Steadybox

Oh, grazie, ha un senso: sono vicini allo stesso algoritmo all'inizio senza la vecchia logica del caso speciale, quindi si calpestano l'un l'altro. Penso che rimuoverò semplicemente il bot originale; Non riesco a pensare a una buona ragione per tenerlo in giro.
istocratico

4

Heurist

L' Eurista tratta questo gioco come una probabilità ripetibile, quindi sa dove tracciare la linea.

È anche avaro, quindi offre il minimo indispensabile per vincere quando può.

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

Disclaimer: max_bidè soggetto a modifiche


4

bob_hater

A questo bot non piace Bob e quindi offrirà sempre 2 $ per vincere contro Bob.

class bob_hater:
    def play_round(bob,will,loose):
        return 2

4

Esibire

Questo è quel ragazzo che mette in mostra la sua abilità matematica in situazioni che davvero non richiedono nulla di così complicato. Fino all'ultimo round (in cui va all-in), usa un modello logistico per determinare la sua offerta, più se i suoi nemici hanno una porzione maggiore del loro denaro rimanente.

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)

La curva logistica utilizzata è f (x) = 1 / (1 + e -8 (x-0,5) ), dove x è il rapporto tra il denaro nemico attuale e il denaro potenziale totale del round. Più hanno gli altri, più fa offerte. Questo ha il possibile vantaggio di offrire quasi-ma-non-abbastanza $ 500 al primo turno.


3

AntiMaxer

Abbina l'importo più alto che possiamo permetterci di tutti i soldi dei giocatori. Farà sì che qualsiasi bot che partecipi all-in in quel round venga eliminato.

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)    

3

Bot semplice

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

Quasi uguale al Bot paziente, ma non al paziente. Ottiene un punteggio molto migliore di quello, però.


3

Wingman 2

Se un wingman è buono, due devono essere migliori?

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

Il codice non funzionerà perché è necessario il rientro per le cose della classe
HyperNeutrino,

È interessante notare che entrambi i tuoi wingman sembrano battere il tuo bot originale (il link pastebin contiene il link TIO, che è troppo lungo per la pubblicazione in un commento e anche troppo lungo per gli accorciatori di URL ...)
Steadybox

1
Ho scoperto che i risultati erano molto sensibili al pool di altri bot; piccole variazioni nel valore dell'incremento sembrano avere risultati sproporzionati.
rancid_banana,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.