Leilão de lance lacrado de primeiro preço

32

Resultado final

A competição acabou. Parabéns a hard_coded!

Alguns fatos interessantes:

  • Em 31600 dos 40920 leilões (77,2%), o vencedor da primeira rodada venceu o maior número de rodadas nesse leilão.

  • Se bots de exemplo forem incluídos na competição, os nove primeiros lugares não mudarão, exceto isso, AverageMinee heuristtrocarão de posição.

  • Os 10 principais resultados de um leilão:

[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
  • Contagem empate (número de leilões que o i-th rodada não teve vencedor): [719, 126, 25, 36, 15, 58, 10, 7, 19, 38].

  • Proposta vencedora média da i-ª rodada: [449.4, 855.6, 1100.8, 1166.8, 1290.6, 1386.3, 1500.2, 1526.5, 1639.3, 3227.1].

Placar

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

Neste jogo, simularemos um leilão de oferta selada.

Cada leilão é um jogo para 4 jogadores, composto por 10 rodadas. Inicialmente, os jogadores não têm dinheiro. No início de cada rodada, cada jogador receberá $ 500 e, em seguida, fará seus próprios lances. O lance pode ser qualquer número inteiro não negativo menor ou igual ao valor que eles possuem. Geralmente, quem oferece o maior ganha a rodada. No entanto, para tornar as coisas mais interessantes, se vários jogadores oferecerem o mesmo preço, sua oferta não será levada em consideração (portanto, não será possível vencer a rodada). Por exemplo, se quatro jogadores fazem um lance de 400 400 300 200, o que oferece 300 vitórias; se eles oferecerem 400 400 300 300, ninguém vence. O vencedor deve pagar o que oferece.

Como se trata de um leilão de "oferta selada", o único jogador que saberá sobre a oferta é o vencedor e quanto pagou no início da próxima rodada (para que o jogador saiba quanto todo mundo tem).


Pontuação

Um leilão será realizado para cada combinação possível de 4 jogadores. Ou seja, se houver N bots no total, haverá um leilão N C 4 . O bot que vencer mais rodadas será o vencedor final. No caso de empate, o bot que pagar menos no total vencerá. Se ainda houver um empate, da mesma forma que a licitação, esses empates serão removidos.


Codificação

Você deve implementar uma classe Python 3 com uma função membro play_round(e / __init__ou outras se necessário). play_rounddeve levar 3 argumentos (incluindo auto). O segundo e o terceiro argumento serão, em ordem: o ID do vencedor da rodada anterior, seguido pelo quanto eles pagaram. Se ninguém vencer ou for a primeira rodada, ambos serão -1. Seu ID será sempre 0 e o ID 1-3 será outro jogador em uma ordem determinada apenas pela posição nesta postagem.


Regras adicionais

1. Determinístico: O comportamento da sua função deve depender apenas dos argumentos de entrada em um leilão. Ou seja, você não pode acessar arquivos, horário, variáveis ​​globais ou qualquer coisa que armazene estados entre diferentes leilões ou bots . Se você deseja usar um gerador pseudo-aleatório, é melhor escrevê-lo sozinho (para evitar afetar os programas de outras pessoas, como randomna biblioteca Python lib), e certifique-se de redefini-lo com uma semente fixa na __init__ou na primeira rodada.

2. Três bots por pessoa: você pode enviar no máximo três bots, para poder desenvolver uma estratégia para que seus bots "cooperem" de alguma forma.

3. Não é muito lento: como haverá muitos leilões, verifique se seus bots não serão executados muito lentamente. Seus robôs devem poder terminar pelo menos 1.000 leilões em um segundo.


Controlador

Aqui está o controlador que estou usando. Todos os bots serão importados e adicionados ao bot_listpedido nesta postagem.

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

Exemplos

Se você precisa de um gerador pseudo-aleatório, aqui está um simples.

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

Resultado

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

O vencedor é all_in_bot. Note-se que zero_bote fortytwo_bottêm a mesma pontuação total e, por isso eles são removidos.

Esses bots não serão incluídos na competição. Você pode usá-los se achar que são ótimos.


A competição final será realizada em 23/11/2017 às 14:00 (UTC) . Você pode fazer qualquer alteração nos seus bots antes disso.

Colera Su
fonte
5
Eles recebem 500 dólares a cada rodada ou a cada leilão (que dura 10 rodadas)?
Stewie Griffin
11
A competição @KamilDrakari será reiniciada com o bot ofensor removido da lista.
Colera Su
4
@ Shufflepants É verdade, mas esse é sempre o caso dos desafios do KotH. No passado, algumas pessoas realmente fizeram um bot perto do fim para combater todos os bots até esse ponto. Mas é apenas parte do desafio do estilo KotH. E da maneira que a maioria dos desafios KotH funciona, incluindo este, a vantagem não será tão grande. Você só pode combater tantos bots ao mesmo tempo. Bom primeiro desafio, Colera Su , e bem-vindo ao PPCG! Ansioso pelos resultados. :)
Kevin Cruijssen
4
Aqui está um teste executado no TIO com todos os bots atuais.
Steadybox 11/11
2
É uma corrida acirrada no momento ...
Zaid 22/11

Respostas:

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    

Esse bot é o resultado do treinamento genético contra muitos outros robôs pseudo-aleatórios (e alguns robôs em outras respostas). Passei algum tempo ajustando no final, mas sua estrutura é realmente muito simples.

As decisões são baseadas apenas em um conjunto fixo de parâmetros e não no resultado das rodadas anteriores.

A chave parece ser a primeira rodada: você precisa apostar tudo, licitar 500 é a jogada segura. Muitos bots estão tentando enganar a jogada inicial, oferecendo 499 ou 498. Ganhar a primeira rodada dá uma grande vantagem para o resto do leilão. Você está com apenas 500 dólares e tem tempo para se recuperar.

Uma aposta segura no segundo turno é um pouco acima de 990, mas mesmo o lance de 0 dá um bom resultado. Lances muito altos e ganhar podem ser piores do que perder nesta rodada.

Na terceira rodada, a maioria dos bots para de subir: 50% deles têm menos de 1.500 dólares agora, então não há necessidade de desperdiçar dinheiro nessa rodada, 1170 é uma boa escolha. A mesma coisa na quarta rodada. Se você perdeu os três primeiros, poderá ganhar este muito barato e ainda ter dinheiro suficiente para o próximo.

Depois disso, o dinheiro médio necessário para ganhar uma rodada é de 1.500 dólares (que é a conclusão lógica: todos já ganham uma rodada em quatro), apostar menos para ganhar mais tarde está apenas desperdiçando dinheiro, a situação se estabilizou e é apenas rodada- a partir de agora).

A última rodada deve ser all-in, e os outros parâmetros são ajustados para vencer a última rodada, oferecendo lances o mais baixo possível até então.

Muitos bots tentam ganhar a nona rodada oferecendo mais de 2.000 dólares, então eu levei isso em consideração e tentei superá-los (não posso vencer as duas últimas rodadas de qualquer maneira, e a última será mais difícil).

GB
fonte
11
Bem, essa é uma maneira de ganhar. Parabéns!
Luca H #
Mas tenho que admitir que gosto mais de outros envios, porque houve outra forma de pensar. Não tentando descobrir como eu venceria contra esses outros bots, mas o que poderia ser uma boa tática contra qualquer bot aleatório.
Luca H
Entendo, gostei (e votei com voto positivo) de outros envios, mas esse é um problema em um domínio finito e muitos envios são muito complexos. O núcleo do problema está gerando uma sequência de 10 números, então optei por otimizar um domínio específico em vez de encontrar um procedimento geral. Eu sou um engenheiro, não um matemático.
GB
2
@LucaH, a aparente simplicidade da abordagem esconde a quantidade de trabalho necessária para chegar a esse conjunto específico de números. Eu estava tentando uma coisa semelhante com o meu próprio bot do ponto de vista estatístico, e não foi fácil
Zaid
11
@Zaid, é claro que há muito trabalho, mas a força bruta é tão bruta;);
Luca H
12

Acima da média

Lances acima da quantidade média de dinheiro que os outros jogadores têm. Oferece tudo na última rodada.

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
fonte
12

Eu nem

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)

Participa apenas em rodadas ímpares e na última rodada.

Dennis
fonte
7

O bot esquecido não sabe quanto dinheiro ele tem, então ele apenas coloca o dinheiro que lhe foi dado para esta rodada. Se ele achar que tem algum dinheiro no final, ele apenas o doará para uma instituição de caridade.

class forgetful_bot:
  def play_round(self, winner, amt):
    return 500
RamenChef
fonte
15
Eu não sou o downvoter, mas talvez seja porque você não colocou qualquer esforço em seu bot
Mischa
9
Esta é uma das primeiras respostas. Algo é necessário para fazer a bola rolar.
Khuldraeseth na'Barya
Não diminuí a votação, mas talvez seja porque, mesmo que algo seja necessário para fazer a bola rolar, talvez faça algo um pouco mais interessante? Especialmente porque isso é praticamente idêntico ao One Dollar Bob que foi usado para obtê-lo tipo de começou
HyperNeutrino
7

One Upper

Eu não sei muito sobre Python, então eu posso cometer algum tipo de erro

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

faz lances 1 mais altos que o lance vencedor anterior ou entra all-in durante a última rodada.

No futuro, posso decidir sobre uma estratégia diferente para quando win_amountfor -1

Kamil Drakari
fonte
7

Patient Bot

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

Não oferece lances para as cinco primeiras rodadas, depois faz lances de ~ 1.000 dólares nas próximas quatro rodadas e, finalmente, oferece tudo o que tem na última rodada.

Steadybox
fonte
7

Copycat Or Sad

Terceiro e último bot.
Este bot oferecerá exatamente o mesmo valor que o vencedor anterior (incluindo ele próprio). No entanto, se não tiver dinheiro suficiente para isso, será triste e oferecerá uma nota de 1 dólar com uma lágrima nele. Na rodada final, ele vai 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

Eu nunca programa em Python, então se você encontrar algum erro, me avise.

Kevin Cruijssen
fonte
2
Isso faz lances -1no primeiro leilão.
Okx 09/11/19
7

Execução de teste

Editei um teste anterior realizado pela Steadybox, adicionando os envios mais recentes.

Estou postando aqui para que haja um local em que o link possa ser atualizado com versões mais recentes. Este post é um wiki da comunidade. Portanto, fique à vontade para atualizá-lo se você postar um novo envio, modificar um antigo ou simplesmente ver algo novo de alguma outra submissão!

Aqui está o link para a execução do teste! (TIO)

Leo
fonte
Devo ficar deprimido que meu bot, que deveria ser perturbador, supere minhas duas finalizações "reais"?
187177
@thegreatemu É interessante ver como os bots interagem entre si. Um único bot novo pode mudar drasticamente a classificação. Algo interessante que eu achei é que, se o bot excluído da lista negra do histocrat participa, meus dois bots passam para o topo do ranking. :)
Jo.
6

Metade em

Este bot sempre oferece metade do que restou, exceto na rodada final, onde irá 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

Eu nunca programa em Python, então se você encontrar algum erro, me avise.

Kevin Cruijssen
fonte
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

Inspirado pelo lista negra enviada pelo histocrat , este bot mantém na memória todas as apostas vencedoras anteriores de outros jogadores, tanto na proporção do dinheiro que apostou em relação ao seu dinheiro total quanto na diferença entre o valor da aposta e o valor total. Para evitar perder para um empate (o que aparentemente é realmente um grande fator nessa competição), evita apostar qualquer número que possa dar os mesmos resultados, considerando o dinheiro atual de seus oponentes.

EDIT: como o valor inicial da oferta agora usa o mínimo entre: seu dinheiro atual, 1 a mais que o dinheiro do oponente mais rico, X a mais que a última aposta vencedora ou Y a mais que o dinheiro médio de seus oponentes. X e Y são constantes que provavelmente serão modificadas antes do final da competição.

Leo
fonte
6

AverageMine

Este jogador calcula a porcentagem (lance / dinheiro total) do vencedor de cada rodada e oferece seu (dinheiro total * porcentagem média de ganhos + 85), a menos que ele tenha mais dinheiro do que todos os outros jogadores, e depois lances 1 a mais que o maior competidor . Começa com uma oferta de 99,0% do valor inicial.

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.
fonte
6

Eenie Meanie Mais

Este jogador é idêntico ao Meanie, exceto por uma variável. Esta versão oferece lances mais agressivos e faz com que alguns jogadores gastem mais do que isso significa que o leilão vale a 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])
Não
fonte
5

Distribuidor

Quando esse bot perde uma rodada, ele distribui o excesso de dinheiro entre todas as próximas rodadas. Ele coloca $ 499 na primeira rodada pensando que os outros empatam com $ 500 e serão eliminados.

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
fonte
11
Usar em roundsvez de self.roundscausará erros. O mesmo com money.
Jeremy Weirich
5

Meanie

Este jogador recebe o dinheiro total que entrará no jogo para obter o lance médio entre o número de jogadores e as rodadas restantes. Se esse objetivo é mais do que todos os outros jogadores atualmente mantêm, reduz sua oferta para o saldo de seu maior concorrente mais um. Se o jogador não puder pagar o seu alvo, é 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])
Não
fonte
5

Vença o vencedor

Faça lances 1 a mais do que o jogador com mais vitórias até agora

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
fonte
4
Você está m,wna ordem correta?
Jo.
5

Menos um

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
fonte
5

Lance mais alto

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

Ainda aprendendo python; faça um lance um pouco maior que o último vencedor.

rancid_banana
fonte
Bem-vindo ao PPCG! Parece que seu bot obtém uma pontuação ainda melhor se você mudar inc = 100para inc = 101.
Steadybox
Eu estou realmente indo contra meus próprios interesses aqui, mas você pode facilmente melhorar sua pontuação, acompanhando os turnos e fazendo all-in na rodada final;)
Leo
Obrigado pelas sugestões; Eu adicionei uma última rodada all-in, afinado o incremento, e acrescentou um par de Wingmen bots para dar a este bot um impulso ..
rancid_banana
Olá, espero que você não se importe, mas eu estava montando um testbench com todo o envio atual e descobri que seu código às vezes retornava valores inválidos na última rodada, então corrigi o bug reorganizando a ordem algumas linhas. Desculpe se mudei algo que você não teria, sinta-se à vontade para reverter as alterações e corrigir o bug de outra maneira!
Leo
@Leo: Não tem problema, obrigado por ter tomado um interesse ..
rancid_banana
4

FiveFiveFive

Pula a primeira rodada e oferece $ 555 nas rodadas restantes. Na última rodada, será all-in, a menos que outros dois bots tenham a mesma quantidade (e presumivelmente serão empatados).

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
fonte
4

Quase tudo 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

Sempre lances um pouco menos do que tem.

Dennis
fonte
4

Escalando rapidamente

Lances para aumentar frações de dinheiro a cada rodada (entre em contato se houver algum erro, um tempo desde que eu usei o 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
Scott
fonte
4

Abaixo da média

Semelhante à média acima, mas fica um pouco menor

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
fonte
4

Cavalo alto

Este jogador oferece todo o seu dinheiro menos o número da rodada atual, exceto na última rodada, onde ele entra.

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.
fonte
4

Swapper

Alterna entre licitar um abaixo do máximo e entrar 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

Achei que precisava encontrar algo que pudesse superar o menos_one do Steadybox. :)

Jo.
fonte
4

Lista negra modular

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

Aposte o valor mais alto possível, que não seja o módulo 500 congruente, para quaisquer números já vistos antes.

Editado para não aplicar a lista negra quando pode obter uma vitória garantida.

histocrata
fonte
Curiosamente, parece que a atualização mais recente do seu outro bot está afetando negativamente esse bot. Atualmente, blacklist_modé o quinto na tabela de classificação , enquanto blacklistestá em segundo lugar. Se a versão mais antiga blacklistfor usada, ela blacklistcai para o sexto lugar, mas blacklist_mod assume a liderança !
Steadybox
Jogar blacklistfora completamente parece dar blacklist_moduma vantagem ainda mais sólida , mas isso é inconclusivo.
Steadybox
Ah, obrigado, isso faz sentido - eles estão próximos do mesmo algoritmo desde o início, sem a velha lógica de casos especiais, então pisam nos dedos uns dos outros. Eu acho que vou remover o bot original; Não consigo pensar em um bom motivo para mantê-lo por perto.
histocrat
4

Heurista

O Heurista trata esse jogo como um de probabilidade repetível, por isso sabe onde traçar a linha.

Também é avarento, por isso oferece o mínimo necessário para uma vitória, quando possível.

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

Isenção de responsabilidade: max_bidestá sujeito a alterações

Zaid
fonte
4

bob_hater

Este bot não gosta de Bob e, portanto, sempre oferecerá 2 $ para ganhar contra Bob.

class bob_hater:
    def play_round(bob,will,loose):
        return 2
Luca H
fonte
4

Mostrar

Esse é o cara que mostra sua habilidade matemática em situações que realmente não exigem nada tão complicado. Até a última rodada (na qual ele faz all-in), ele usa um modelo de logística para determinar sua oferta, mais se seus inimigos tiverem uma parcela maior de seu dinheiro restante.

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)

A curva logística utilizada é f (x) = 1 / (1 + e -8 (x-0,5) ), onde x é a razão entre o dinheiro inimigo atual e o total de dinheiro inimigo potencial da rodada. Quanto mais os outros têm, mais ele oferece. Isso tem o possível benefício de oferecer quase US $ 500, mas não exatamente, na primeira rodada.

Khuldraeseth na'Barya
fonte
3

AntiMaxer

Combine a quantia mais alta que pudermos pagar do dinheiro de todos os jogadores. Irá causar qualquer empate no all-in nessa rodada.

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
fonte
3

Simple 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

Quase o mesmo que Patient Bot, mas não como paciente. Obtém uma pontuação muito melhor do que isso, no entanto.

Steadybox
fonte
3

Wingman 2

Se um ala é bom, dois devem ser melhores?

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
fonte
Seu código não vai funcionar porque você precisa recuo para o material na classe
HyperNeutrino
Curiosamente, ambas as alas parecem bater o seu bot originais (o link pastebin contém o link TIO, o que é muito tempo para postar em um comentário e até mesmo muito tempo para Redutores de URL ...)
Steadybox
11
Eu achei que os resultados eram muito sensíveis ao pool de outros bots; pequenas alterações no valor do incremento parecem ter resultados desproporcionais.
rancid_banana