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,
AverageMine
eheurist
trocarã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_round
deve 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 random
na 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_list
pedido 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_bot
e fortytwo_bot
tê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.
fonte
Respostas:
hard_coded
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).
fonte
Acima da média
Lances acima da quantidade média de dinheiro que os outros jogadores têm. Oferece tudo na última rodada.
fonte
Eu nem
Participa apenas em rodadas ímpares e na última rodada.
fonte
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.
fonte
One Upper
Eu não sei muito sobre Python, então eu posso cometer algum tipo de erro
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_amount
for -1fonte
Patient Bot
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.
fonte
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.
Eu nunca programa em Python, então se você encontrar algum erro, me avise.
fonte
-1
no primeiro leilão.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)
fonte
Metade em
Este bot sempre oferece metade do que restou, exceto na rodada final, onde irá all in.
Eu nunca programa em Python, então se você encontrar algum erro, me avise.
fonte
Graylist
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.
fonte
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.
fonte
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.
fonte
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.
fonte
rounds
vez deself.rounds
causará erros. O mesmo commoney
.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.
fonte
Vença o vencedor
Faça lances 1 a mais do que o jogador com mais vitórias até agora
fonte
m,w
na ordem correta?Menos um
fonte
Lance mais alto
Ainda aprendendo python; faça um lance um pouco maior que o último vencedor.
fonte
inc = 100
parainc = 101
.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).
fonte
Quase tudo dentro
Sempre lances um pouco menos do que tem.
fonte
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)
fonte
Abaixo da média
Semelhante à média acima, mas fica um pouco menor
fonte
Cavalo alto
Este jogador oferece todo o seu dinheiro menos o número da rodada atual, exceto na última rodada, onde ele entra.
fonte
Swapper
Alterna entre licitar um abaixo do máximo e entrar all-in.
Achei que precisava encontrar algo que pudesse superar o menos_one do Steadybox. :)
fonte
Lista negra modular
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.
fonte
blacklist_mod
é o quinto na tabela de classificação , enquantoblacklist
está em segundo lugar. Se a versão mais antigablacklist
for usada, elablacklist
cai para o sexto lugar, masblacklist_mod
assume a liderança !blacklist
fora completamente parece darblacklist_mod
uma vantagem ainda mais sólida , mas isso é inconclusivo.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.
Isenção de responsabilidade:
max_bid
está sujeito a alteraçõesfonte
bob_hater
Este bot não gosta de Bob e, portanto, sempre oferecerá 2 $ para ganhar contra Bob.
fonte
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.
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.
fonte
AntiMaxer
Combine a quantia mais alta que pudermos pagar do dinheiro de todos os jogadores. Irá causar qualquer empate no all-in nessa rodada.
fonte
Simple Bot
Quase o mesmo que Patient Bot, mas não como paciente. Obtém uma pontuação muito melhor do que isso, no entanto.
fonte
Wingman 2
Se um ala é bom, dois devem ser melhores?
fonte