Subasta de primer precio de oferta sellada

32

Resultado final

La competencia ha terminado. ¡Felicidades a hard_coded!

Algunos hechos interesantes:

  • En 31600 de 40920 subastas (77,2%), el ganador de la primera ronda ganó la mayor cantidad de rondas en esa subasta.

  • Si se incluyen bots de ejemplo en la competencia, los nueve primeros lugares no cambiarán excepto eso AverageMiney heuristcambiarán sus posiciones.

  • Los 10 resultados principales en una subasta:

[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
  • Recuento de lazo (número de subastas que el i-ª ronda no tuvo ganador): [719, 126, 25, 36, 15, 58, 10, 7, 19, 38].

  • Promedio oferta ganadora de la i-ª ronda: [449.4, 855.6, 1100.8, 1166.8, 1290.6, 1386.3, 1500.2, 1526.5, 1639.3, 3227.1].

Marcador

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

En este juego, simularemos una subasta de oferta sellada.

Cada subasta es un juego de 4 jugadores, consta de 10 rondas. Inicialmente, los jugadores no tienen dinero. Al comienzo de cada ronda, cada jugador recibirá $ 500 y luego hará sus propias ofertas. La oferta puede ser cualquier número entero no negativo menor o igual que la cantidad que tienen. Por lo general, quien apuesta más alto gana la ronda. Sin embargo, para hacer las cosas más interesantes, si varios jugadores ofertan el mismo precio, su oferta no se tendrá en cuenta (por lo tanto, no puede ganar la ronda). Por ejemplo, si cuatro jugadores ofertan 400 400 300 200, el que ofrece 300 gana; si ofertan 400 400 300 300, nadie gana. El ganador debe pagar lo que oferte.

Como se trata de una subasta de "oferta sellada", la única información que el jugador sabrá sobre la oferta es el ganador y cuánto pagaron cuando comience la próxima ronda (para que el jugador pueda saber cuánto tienen todos).


Tanteo

Se realizará una subasta por cada combinación posible de 4 jugadores. Es decir, si hay N bots en total, habrá una subasta de N C 4 . El bot que gane más rondas será el ganador final. En el caso de que haya un empate, el bot que pagó menos en total ganará. Si todavía hay un empate, de la misma manera que la licitación, esos lazos se eliminarán.


Codificación

Debe implementar una clase Python 3 con una función miembro play_round(y __init__otras si es necesario). play_rounddebe tomar 3 argumentos (incluido uno mismo). El segundo y tercer argumento serán, en orden: la identificación del ganador de la ronda anterior, seguida de cuánto pagaron. Si nadie gana o es la primera ronda, ambos serán -1. Su identificación siempre será 0, y la identificación 1–3 serán otros jugadores en un orden solo determinado por la posición en esta publicación.


Reglas adicionales

1. Determinista: el comportamiento de su función debe depender solo de los argumentos de entrada dentro de una subasta. Es decir, no puede acceder a archivos, tiempo, variables globales o cualquier cosa que almacene estados entre diferentes subastas o bots . Si desea usar un generador pseudoaleatorio, es mejor escribirlo usted mismo (para evitar afectar los programas de otros, como randomen Python lib), y asegúrese de restablecerlo con una semilla fija __init__o la primera ronda.

2. Tres bots por persona: puede enviar como máximo 3 bots, por lo que puede desarrollar una estrategia para hacer que sus bots "cooperen" de alguna manera.

3. No es demasiado lento: dado que habrá muchas subastas, asegúrese de que sus bots no funcionen demasiado lento. Sus bots deberían poder terminar al menos 1,000 subastas en un segundo.


Controlador

Aquí está el controlador que estoy usando. Todos los bots se importarán y agregarán bot_listen el orden de esta publicación.

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

Ejemplos

Si necesita un generador pseudoaleatorio, aquí hay uno simple.

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

El ganador es all_in_bot. Tenga en cuenta que zero_boty fortytwo_bottienen el mismo puntaje y total, por lo que se eliminan.

Estos bots no se incluirán en la competencia. Puedes usarlos si crees que son geniales.


La competencia final se llevará a cabo el 23/11/2017 a las 14:00 (UTC) . Puedes hacer cualquier cambio en tus bots antes de eso.

Colera Su
fuente
55
¿Obtienen 500 dólares cada ronda o cada subasta (que dura 10 rondas)?
Stewie Griffin
1
La competencia de @KamilDrakari se reiniciará con el bot infractor eliminado de la lista.
Colera Su
44
@Shufflepants Cierto, pero este es siempre el caso con los desafíos de KotH. En el pasado, algunas personas hicieron un bot cerca del final para contrarrestar todos los bots hasta ese momento. Pero es solo parte del desafío al estilo KotH. Y como funciona la mayoría de los desafíos de KotH, incluido este, la ventaja no será tan buena. Solo puedes contrarrestar tantos bots al mismo tiempo. ¡Buen primer desafío, Colera Su , y bienvenido a PPCG! Mirando hacia adelante a los resultados. :)
Kevin Cruijssen
44
Aquí hay una prueba de funcionamiento en TIO con todos los bots actuales.
Steadybox
2
Es una carrera apretada en este momento ...
Zaid

Respuestas:

13

codificado

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    

Este bot es el resultado del entrenamiento genético contra muchos otros bots pseudoaleatorios (y algunos de los bots en otras respuestas). He pasado algún tiempo afinando al final, pero su estructura es realmente muy simple.

Las decisiones se basan solo en un conjunto fijo de parámetros y no en el resultado de rondas anteriores.

La clave parece ser la primera ronda: tienes que ir todo adentro, apostar 500 es el movimiento seguro. Demasiados bots intentan burlar el movimiento inicial haciendo una oferta de 499 o 498. Ganar la primera ronda te da una gran ventaja para el resto de la subasta. Solo tiene 500 dólares de retraso y tiene tiempo para recuperarse.

Una apuesta segura en la segunda ronda es un poco más de 990, pero incluso apostar 0 da un buen resultado. Apostar demasiado alto y ganar podría ser peor que perder esta ronda.

En la tercera ronda, la mayoría de los bots dejan de escalar: el 50% de ellos tienen menos de 1500 dólares por ahora, por lo que no hay necesidad de gastar dinero en esta ronda, 1170 es una buena compensación. Lo mismo en la cuarta ronda. Si perdió los primeros tres, puede ganar este muy barato y aún tener suficiente dinero para el próximo.

Después de eso, el dinero promedio requerido para ganar una ronda es de 1500 dólares (que es la conclusión lógica: todos ganan una ronda de cuatro por ahora, apostar menos para ganar más tarde es solo malgastar dinero, la situación se ha estabilizado y es solo una ronda- Robin de ahora en adelante).

La última ronda debe ser all-in, y los otros parámetros están ajustados para ganar la última ronda haciendo una oferta lo más baja posible hasta entonces.

Muchos bots intentan ganar la novena ronda haciendo una oferta de más de 2000 dólares, así que tomé eso en cuenta e intenté abusar de ellos (de todos modos no puedo ganar las dos últimas rondas, y la última será más difícil).

GB
fuente
1
Bueno, esa es una forma de ganar. ¡Felicidades!
Luca H
Pero debo admitir que me gustan más otras presentaciones, porque hubo otra forma de pensar. No estoy probando cómo ganaría contra esos otros bots, pero cuál podría ser una buena táctica contra cualquier bot aleatorio.
Luca H
Puedo entender, me gustaron (y voté) algunas otras presentaciones, pero este es un problema en un dominio finito, y muchas presentaciones son demasiado complejas. El núcleo del problema es generar una secuencia de 10 números, por lo que elegí optimizar para un dominio específico en lugar de encontrar un procedimiento general. Soy ingeniero, no matemático.
GB
2
@LucaH la aparente simplicidad del enfoque desmiente la cantidad de trabajo requerido para llegar a este conjunto particular de números. Estaba intentando algo similar con mi propio bot desde un punto de vista estadístico, y no fue fácil
Zaid el
1
@Zaid, por supuesto, hay mucho trabajo en juego, pero el forzamiento bruto es tan ... bruto;)
Luca H
12

Por encima del promedio

Ofertas superiores a la cantidad promedio de dinero que tienen los otros jugadores. Ofrece todo en la última ronda.

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

Ni siquiera

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)

Solo participa en rondas impares y en la última ronda.

Dennis
fuente
7

El bot olvidadizo no sabe cuánto dinero tiene, por lo que solo pone el dinero que le dieron para esta ronda. Si descubre que tiene algo de dinero al final, simplemente lo dona a una organización benéfica.

class forgetful_bot:
  def play_round(self, winner, amt):
    return 500
RamenChef
fuente
15
No soy el votante negativo, pero tal vez lo sea porque no pusiste ningún esfuerzo en tu bot
Mischa
99
Esta es una de las primeras respuestas. Se necesita algo para hacer rodar la pelota.
Khuldraeseth na'Barya
No voté en contra, pero tal vez sea porque, aunque algo necesitaba hacer rodar la pelota, ¿tal vez hacer algo un poco más interesante? Especialmente porque esto es prácticamente idéntico a One Dollar Bob, que se usó para comenzar
HyperNeutrino el
7

Un superior

No sé mucho sobre Python, por lo que podría cometer algún tipo de error

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

ofrece 1 más alto que la oferta ganadora anterior, o va todo adentro durante la última ronda.

Puede que en el futuro decida una estrategia diferente para cuándo win_amountes -1

Kamil Drakari
fuente
7

Bot paciente

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

No ofrece nada para las primeras cinco rondas, luego ofrece ~ 1000 dólares para las siguientes cuatro rondas, y finalmente ofrece todo lo que tiene en la última ronda.

Steadybox
fuente
7

Imitador o triste

Tercer y último bot.
Este bot ofertará exactamente la misma cantidad que el ganador anterior (incluido él mismo). Sin embargo, si no tiene suficiente efectivo para hacerlo, será triste y, en su lugar, ofertará un billete de 1 dólar con su rasgadura. En la ronda final irá todo adentro.

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

Nunca programo en Python, así que si ves algún error avísame ...

Kevin Cruijssen
fuente
2
Esto hace una oferta -1en la primera subasta.
Okx
7

Prueba de funcionamiento

He editado una prueba anterior realizada por Steadybox agregando las presentaciones más recientes.

Lo estoy publicando aquí, así que hay un lugar donde el enlace se puede actualizar con versiones más recientes, esta publicación es un wiki de la comunidad, así que siéntase libre de actualizarla si publica una nueva presentación, modifica una antigua o simplemente ve algo ¡nuevo de alguna otra presentación!

Aquí está el enlace a la prueba de funcionamiento! (TIO)

Leo
fuente
¿Debería estar deprimido de que mi robot que estaba destinado a ser disruptivo supera mis dos presentaciones "reales"?
thegreatemu
@thegreatemu Es interesante ver cómo los bots interactúan entre sí. Un solo nuevo robot podría cambiar drásticamente la clasificación. Algo interesante que encontré es que si el bot eliminado de la lista negra de histocrat participa, mis dos bots pasan a la parte superior de la clasificación. :)
Jo.
6

Medio

Este bot siempre ofrece la mitad de lo que le queda, excepto en la ronda final donde irá todo.

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

Nunca programo en Python, así que si ves algún error avísame ...

Kevin Cruijssen
fuente
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 por el presentación de lista negra por el histocrat , este bot guarda en la memoria todas las apuestas ganadoras anteriores de otros jugadores como la proporción de dinero que apostaron en comparación con su dinero completo y la diferencia entre el monto de su apuesta y el monto total. Para evitar perder ante un empate (que aparentemente es un factor importante en esta competencia), evita apostar cualquier número que pueda dar los mismos resultados dado el dinero actual de sus oponentes.

EDITAR: como el valor inicial de la oferta ahora usa el mínimo entre: su dinero actual, 1 más que el dinero del oponente más rico, X más que la última apuesta ganadora, o Y más que el dinero promedio de sus oponentes. X e Y son constantes que probablemente se modificarán antes del final de la competencia.

León
fuente
6

PromedioMine

Este jugador calcula el porcentaje (oferta / dinero total) para el ganador de cada ronda y ofrece su (dinero total * porcentaje de ganancia promedio + 85) a menos que tenga más dinero que todos los demás jugadores, luego ofrece 1 más que el competidor más alto . Comienza con una oferta del 99.0% del monto 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
fuente
6

Eenie Meanie Más

Este jugador es idéntico a Meanie, excepto por una variable. Esta versión hace ofertas más agresivas y hace que algunos jugadores gasten más de lo que los malvados creen que vale la subasta.

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])
No
fuente
5

Distribuidor

Cuando este bot pierde una ronda, distribuye el exceso de efectivo entre todas las siguientes rondas. Pone $ 499 en la primera ronda pensando que los otros empatarán con $ 500 y serán 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
fuente
1
Usar en roundslugar de self.roundscausará errores. Lo mismo con money.
Jeremy Weirich
5

Malvado

Este jugador toma el efectivo total que entrará en juego para obtener la oferta promedio a través del número de jugadores y las rondas restantes. Si este objetivo es más de lo que todos los demás jugadores tienen actualmente, reduce su oferta al saldo de su mayor competidor más uno. Si el jugador no puede pagar su objetivo, está todo incluido.

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])
No
fuente
5

Vencer al ganador

Puja 1 más que el jugador con más victorias hasta ahora

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
fuente
44
¿Estás m,wen el orden correcto?
Jo.
5

Menos 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
Steadybox
fuente
5

Oferta mayor

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

Todavía estoy aprendiendo python; oferte un poco más alto que el último ganador.

rancid_banana
fuente
Bienvenido a PPCG! Parece que tu bot obtiene una puntuación aún mejor si cambias inc = 100a inc = 101.
Steadybox
Realmente estoy yendo en contra de mis propios intereses aquí, pero podrías mejorar fácilmente tu puntaje haciendo un seguimiento de los giros y yendo todo adentro en la ronda final;)
Leo
Gracias por las sugerencias; Agregué un all-in de la última ronda, ajusté el incremento y agregué un par de robots de wingmen para darle un impulso a este bot ...
rancid_banana
Hola, espero que no te importe, pero estaba armando un banco de pruebas con todo el envío actual y descubrí que tu código a veces devolvía valores no válidos en la última ronda, así que solucioné el error reorganizando El orden de un par de líneas. Lo siento si cambié algo que no hubieras tenido, ¡no dudes en revertir los cambios y corregir el error de otra manera!
Leo
@Leo: No hay problema, gracias por interesarse ...
rancid_banana
4

FiveFiveFive

Se salta la primera ronda y ofrece $ 555 en las rondas restantes. En la última ronda, entrará todo a menos que otros 2 bots tengan la misma cantidad (y presumiblemente se vincularán).

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

Casi todo adentro

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

Siempre ofrece un poco menos de lo que tiene.

Dennis
fuente
4

Escalando rápidamente

Ofrece cada vez más fracciones de su dinero (por favor avíseme si hay algún error, un tiempo desde que usé 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
fuente
4

Debajo del promedio

Similar al promedio superior, pero va un poco más bajo

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

Caballo alto

Este jugador ofrece todo su dinero menos el número de la ronda actual, excepto en la última ronda, donde ingresa todo.

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

Swapper

Alterna entre hacer una oferta por debajo de su máximo y entrar todo.

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

Pensé que necesitaba encontrar algo que pudiera vencer al menos_uno de Steadybox. :)

Jo
fuente
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

Apuesta la mayor cantidad posible que no sea congruente módulo 500 a cualquier número que se haya visto antes.

Editado para no aplicar la lista negra cuando puede obtener una victoria garantizada.

histocrat
fuente
Curiosamente, parece que la última actualización de su otro bot está afectando negativamente a este bot. Actualmente, blacklist_modes quinto en la clasificación , mientras que blacklistestá en segundo lugar. Si en su blacklistlugar se usa la versión anterior , blacklistcae al sexto lugar, ¡pero blacklist_mod toma la delantera !
Steadybox
Tirar blacklistpor completo parece dar blacklist_moduna ventaja aún más sólida , pero eso no es concluyente.
Steadybox
Oh, gracias, eso tiene sentido: están cerca del mismo algoritmo desde el principio sin la vieja lógica de casos especiales, por lo que pisan los pies de los demás. Creo que simplemente eliminaré el bot original; No puedo pensar en una buena razón para mantenerlo.
histocrat
4

Heurista

El heurista trata este juego como uno de probabilidad repetible, por lo que sabe dónde trazar la línea.

También es tacaño, por lo que ofrece el mínimo requerido para ganar cuando puede.

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

Descargo de responsabilidad: max_bidestá sujeto a cambios

Zaid
fuente
4

bob_hater

A este bot no le gusta Bob y, por lo tanto, siempre ofrecerá 2 $ para ganar contra Bob.

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

Presumir

Este es ese tipo que muestra su habilidad matemática en situaciones que realmente no requieren nada tan complicado. Hasta la última ronda (en la que va todo adentro), usa un modelo logístico para determinar su oferta, más si sus enemigos tienen una porción mayor de su dinero 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)

La curva logística utilizada es f (x) = 1 / (1 + e -8 (x-0.5) ), donde x es la relación entre el dinero enemigo actual y el dinero enemigo potencial total de la ronda. Cuanto más tienen los demás, más puja. Esto tiene el posible beneficio de hacer una oferta de casi $ 500 la primera ronda.

Khuldraeseth na'Barya
fuente
3

AntiMaxer

Iguala la cantidad más alta que podemos pagar del dinero de todos los jugadores. Hará que cualquier bot que vaya a all-in en esa ronda se empate.

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

Bot simple

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

Casi lo mismo que Patient Bot, pero no como paciente. Sin embargo, obtiene una puntuación mucho mejor.

Steadybox
fuente
3

Wingman 2

Si un wingman es bueno, ¿dos deben ser mejores?

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
fuente
Su código no funcionará porque necesita sangrado para las cosas en la clase
HyperNeutrino
Curiosamente, sus dos compañeros de ala parecen vencer a su bot original (el enlace pastebin contiene el enlace TIO, que es demasiado largo para publicar en un comentario e incluso demasiado para acortadores de URL ...)
Steadybox
1
Descubrí que los resultados eran muy sensibles al conjunto de otros robots; cambios menores en el valor del incremento parecen tener resultados desproporcionados.
rancid_banana