Enchères aux enchères scellées au premier prix


32

Résultat final

La compétition est finie. Félicitations à hard_coded!

Quelques faits intéressants:

  • Dans 31600 enchères sur 40920 (77,2%), le vainqueur du premier tour a remporté le plus de tours de cette enchère.

  • Si des exemples de bots sont inclus dans la compétition, les neuf premières places ne changeront pas sauf cela AverageMineet heuristéchangeront leurs positions.

  • Top 10 des résultats d'une vente aux enchères:

[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
  • Comte Tie (nombre de ventes aux enchères que le i-ème tour avait pas de gagnant): [719, 126, 25, 36, 15, 58, 10, 7, 19, 38].

  • Offre publique moyen gagnant du i-ème tour: [449.4, 855.6, 1100.8, 1166.8, 1290.6, 1386.3, 1500.2, 1526.5, 1639.3, 3227.1].

Tableau d'affichage

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

Dans ce jeu, nous simulerons une vente aux enchères scellée.

Chaque enchère est un jeu à 4 joueurs, composé de 10 tours. Au départ, les joueurs n'ont pas d'argent. Au début de chaque tour, chaque joueur recevra 500 $, puis fera ses propres enchères. L'enchère peut être un entier non négatif inférieur ou égal au montant dont ils disposent. Habituellement, celui qui offre le plus haut remporte la manche. Cependant, pour rendre les choses plus intéressantes, si plusieurs joueurs offrent le même prix, leur enchère ne sera pas prise en compte (donc ne peut pas gagner le tour). Par exemple, si quatre joueurs enchérissent 400 400 300 200, celui enchérit 300 victoires; s'ils enchérissent 400 400 300 300, personne ne gagne. Le gagnant doit payer ce qu'il a offert.

Puisqu'il s'agit d'une enchère «à enchères scellées», le seul joueur qui connaîtra les enchères est le gagnant et combien il a payé au début du prochain tour (afin que le joueur puisse savoir combien chacun a).


Notation

Une enchère aura lieu pour chaque combinaison possible de 4 joueurs. Autrement dit, s'il y a N bots au total, il y aura une enchère N C 4 . Le bot qui remportera le plus de tours sera le vainqueur final. En cas d'égalité, le bot qui a payé le moins au total gagnera. S'il y a toujours une égalité, de la même manière que l'enchère, ces égalités seront supprimées.


Codage

Vous devez implémenter une classe Python 3 avec une fonction membre play_round(et __init__ou d'autres si vous en avez besoin). play_rounddevrait prendre 3 arguments (y compris l'auto). Les deuxième et troisième arguments seront, dans l'ordre: l'identifiant du vainqueur du tour précédent, suivi du montant qu'ils ont payé. Si personne ne gagne ou que c'est le premier tour, ils seront tous les deux -1. Votre identifiant sera toujours 0 et les identifiants 1 à 3 seront les autres joueurs dans un ordre uniquement déterminé par la position sur ce post.


Règles supplémentaires

1. Déterministe: le comportement de votre fonction ne devrait dépendre que des arguments d'entrée dans une enchère. Autrement dit, vous ne pouvez pas accéder aux fichiers, à l'heure, aux variables globales ou à tout ce qui stockera des états entre différentes enchères ou bots . Si vous souhaitez utiliser un générateur pseudo-aléatoire, il est préférable de l'écrire par vous-même (pour éviter d'affecter les programmes des autres comme randomdans la bibliothèque Python), et assurez-vous de le réinitialiser avec une graine fixe dans __init__ou au premier tour.

2. Trois bots par personne: vous êtes autorisé à soumettre au plus 3 bots, vous pouvez donc développer une stratégie pour faire coopérer vos bots d'une manière ou d'une autre.

3. Pas trop lent: étant donné qu'il y aura de nombreuses enchères, assurez-vous que vos robots ne fonctionneront pas trop lentement. Vos robots devraient pouvoir terminer au moins 1 000 enchères en une seconde.


Manette

Voici le contrôleur que j'utilise. Tous les bots seront importés et ajoutés bot_listdans l'ordre de cette publication.

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

Exemples

Si vous avez besoin d'un générateur pseudo-aléatoire, en voici un 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

Résultat

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

Le gagnant est all_in_bot. Notez que zero_botet fortytwo_botont le même score et le même total, ils sont donc supprimés.

Ces bots ne seront pas inclus dans la compétition. Vous pouvez les utiliser si vous pensez qu'ils sont géniaux.


La compétition finale aura lieu le 23/11/2017 à 14h00 (UTC) . Vous pouvez apporter des modifications à vos robots avant cela.


5
Obtiennent-ils 500 dollars à chaque tour ou à chaque enchère (qui dure 10 tours)?
Stewie Griffin

1
La compétition @KamilDrakari reprendra avec le bot incriminé retiré de la liste.
Colera Su

4
@Shufflepants C'est vrai, mais c'est toujours le cas avec les défis KotH. Dans le passé, certaines personnes ont en effet créé un bot vers la fin pour contrer tous les bots jusqu'à ce point. Mais cela fait partie du défi de style KotH. Et la façon dont la plupart des défis KotH fonctionnent, celui-ci inclus, l'avantage ne sera pas si grand. Vous ne pouvez contrer autant de bots en même temps .. Beau premier défi, Colera Su , et bienvenue sur PPCG! Dans l'attente des résultats. :)
Kevin Cruijssen

4
Voici un test sur TIO avec tous les bots actuels.
Steadybox

2
C'est une course serrée en ce moment ...
Zaid

Réponses:


13

codé en dur

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    

Ce bot est le résultat d'un entraînement génétique contre beaucoup d'autres robots pseudo-aléatoires (et certains des robots dans d'autres réponses). J'ai passé un peu de temps à affiner à la fin, mais sa structure est en fait très simple.

Les décisions sont basées uniquement sur un ensemble fixe de paramètres et non sur les résultats des cycles précédents.

La clé semble être le premier tour: vous devez faire tapis, enchérir 500 est la solution sûre. Trop de bots essaient de déjouer le coup initial en enchérissant 499 ou 498. Gagner le premier tour vous donne un gros avantage pour le reste de l'enchère. Vous n'avez que 500 dollars de retard et vous avez le temps de récupérer.

Une valeur sûre au deuxième tour est un peu plus de 990, mais même enchérir 0 donne un bon résultat. Enchérir trop haut et gagner pourrait être pire que de perdre ce tour.

Au troisième tour, la plupart des bots cessent de grimper: 50% d'entre eux ont maintenant moins de 1500 dollars, il n'est donc pas nécessaire de gaspiller de l'argent sur ce tour, 1170 est un bon compromis. Même chose au quatrième tour. Si vous avez perdu les trois premiers, vous pouvez gagner celui-ci très bon marché et avoir encore assez d'argent pour le prochain.

Après cela, l'argent moyen requis pour gagner un tour est de 1500 dollars (ce qui est la conclusion logique: tout le monde gagne maintenant un tour sur quatre, enchérir moins pour gagner plus tard ne fait que gaspiller de l'argent, la situation s'est stabilisée et c'est juste un tour- robin à partir de maintenant).

Le dernier tour doit être all-in, et les autres paramètres sont affinés pour gagner le dernier tour en misant le plus bas possible jusque-là.

Beaucoup de bots essaient de gagner le neuvième tour en enchérissant plus de 2000 dollars, alors j'ai pris cela en compte et j'ai essayé de les surenchérir (je ne peux pas gagner les deux derniers tours de toute façon, et le dernier sera plus difficile).


1
Eh bien, c'est une façon de gagner. Toutes nos félicitations!
Luca H

Mais je dois admettre que j'aime davantage les autres soumissions, car il y a eu une autre forme de réflexion. N'essayant pas comment je gagnerais contre ces autres bots, mais quelle pourrait être une bonne tactique contre n'importe quel bot aléatoire.
Luca H

Je peux comprendre, j'ai aimé (et voté) quelques autres soumissions, mais c'est un problème sur un domaine fini, et beaucoup de soumissions sont tout simplement trop complexes. Le cœur du problème est de générer une séquence de 10 nombres, j'ai donc choisi d'optimiser pour un domaine spécifique au lieu de trouver une procédure générale. Je suis ingénieur, pas mathématicien.
GB

2
@LucaH l'apparente simplicité de l'approche dément la quantité de travail requise pour arriver à cet ensemble particulier de nombres. J'essayais une chose similaire avec mon propre bot d'un point de vue statistique, et ce n'était pas facile
Zaid

1
@Zaid, bien sûr, il y a beaucoup de travail, mais le forçage brutal est juste si ... brutal;)
Luca H

12

Au dessus de la moyenne

Des enchères supérieures au montant moyen des autres joueurs. Offre tout au dernier tour.

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

Je ne fais même pas

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)

Ne participe qu'aux tours impairs et au dernier tour.


7

Le bot oublieux ne sait pas combien d'argent il a, alors il met juste l'argent qui lui a été donné pour ce tour. S'il découvre qu'il a de l'argent à la fin, il le donne simplement à un organisme de bienfaisance.

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

15
Je ne suis pas le downvoter, mais c'est peut-être parce que vous n'avez fait aucun effort dans votre bot
Mischa

9
Ceci est l'une des premières réponses. Il faut quelque chose pour faire rouler la balle.
Khuldraeseth na'Barya

Je n'ai pas downvote, mais c'est peut-être parce que même si quelque chose était nécessaire pour faire rouler la balle, peut-être faire quelque chose d'un peu plus intéressant? D'autant plus que c'est pratiquement identique à One Dollar Bob qui a été utilisé pour le faire démarrer
HyperNeutrino

7

One Upper

Je ne sais pas grand chose sur Python, donc je pourrais faire une sorte d'erreur

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

offre 1 de plus que l'enchère gagnante précédente, ou fait tapis lors du dernier tour.

Je pourrai à l'avenir décider d'une stratégie différente pour quand win_amountest -1


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'offre rien pour les cinq premiers tours, puis offre ~ 1000 dollars pour les quatre tours suivants, et finalement offre tout ce qu'il a au dernier tour.


7

Copycat Or Sad

Troisième et dernier bot.
Ce bot offrira exactement le même montant que le gagnant précédent (y compris lui-même). Cependant, s'il n'a pas assez d'argent pour le faire, ce sera triste et il offrira un maigre billet de 1 dollar avec sa larme dessus. Dans le tour final, il fera tapis.

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

Je ne programme jamais en Python, donc si vous voyez des erreurs faites le moi savoir ..


2
Cette offre -1sur la première vente aux enchères.
Okx

7

Essai

J'ai édité un test précédent mis en place par Steadybox en ajoutant les dernières soumissions.

Je le poste ici, donc il y a un endroit où le lien peut être mis à jour avec des versions plus récentes, ce message est un wiki communautaire alors n'hésitez pas à le mettre à jour si vous postez une nouvelle soumission, modifiez une ancienne ou voyez simplement quelque chose nouveau d'une autre soumission!

Voici le lien vers le test! (TIO)


devrais-je être déprimé que mon bot qui était censé être perturbateur bat mes deux "vraies" soumissions?
thegreatemu

@thegreatemu Il est intéressant de voir comment les robots interagissent les uns avec les autres. Un seul nouveau bot pourrait changer radicalement le classement. Quelque chose d'intéressant que j'ai trouvé est que si le bot de la liste noire supprimée de l'histocrate participe, mes deux bots se placent en haut du classement. :)
Jo.

6

Demi dedans

Ce bot offre toujours la moitié de ce qu'il lui reste, sauf au dernier tour où il fera tapis.

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

Je ne programme jamais en Python, donc si vous voyez des erreurs faites le moi savoir ..


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

Inspiré par la soumission de la liste noire par l'histocrate , ce bot garde en mémoire tous les paris gagnants précédents des autres joueurs, à la fois le rapport d'argent qu'ils ont parié par rapport à leur argent total et la différence entre leur montant de pari et le montant total. Afin d'éviter de perdre à égalité (ce qui est apparemment un facteur important dans cette compétition), il évite alors de parier n'importe quel nombre qui pourrait donner les mêmes résultats compte tenu des fonds actuels de ses adversaires.

EDIT: comme la valeur de départ de l'enchère utilise désormais le minimum entre: son argent actuel, 1 de plus que l'argent de l'adversaire le plus riche, X de plus que le dernier pari gagnant, ou Y de plus que l'argent moyen de ses adversaires. X et Y sont des constantes qui seront probablement modifiées avant la fin de la compétition.


6

AverageMine

Ce joueur calcule le pourcentage (enchère / argent total) pour le vainqueur de chaque tour et offre son (argent total * pourcentage de gain moyen + 85) à moins qu'il ait plus d'argent que tous les autres joueurs, puis il offre 1 de plus que le plus haut concurrent . Commence par une enchère de 99,0% du montant de départ.

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 Plus

Ce joueur est identique à Meanie, à l'exception d'une variable. Cette version enchérit de manière plus agressive et fait que certains joueurs dépensent plus que la moyenne ne le pense.

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

Distributeur

Lorsque ce bot perd un tour, il répartit l'excédent d'argent entre tous les tours suivants. Il met 499 $ au premier tour en pensant que les autres seront à égalité avec 500 $ et seront éliminés.

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
Utiliser roundsau lieu de self.roundsprovoquera des erreurs. Même chose avec money.
Jeremy Weirich

5

Meanie

Ce joueur prend l'argent total qui entrera en jeu pour obtenir l'enchère moyenne sur le nombre de joueurs et les tours restants. Si cet objectif est supérieur à ce que tous les autres joueurs détiennent actuellement, il réduit son enchère au solde de son plus grand concurrent plus un. Si le joueur ne peut pas se permettre sa cible, il est 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

Battre le gagnant

Enchérissez 1 de plus que le joueur avec le plus de victoires jusqu'à présent

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
Êtes-vous m,wdans le bon ordre?
Jo.

5

Moins un

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

Enchérissez plus

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

Python toujours en apprentissage; enchérir un peu plus que le dernier gagnant.


Bienvenue chez PPCG! Il semble que votre bot obtienne un score encore meilleur si vous passez inc = 100à inc = 101.
Steadybox

Je vais vraiment à l'encontre de mes propres intérêts ici, mais vous pourriez facilement améliorer votre score en gardant une trace des virages et en faisant tapis au tour final;)
Leo

Merci pour les suggestions; J'ai ajouté un all-in de dernière ronde, affiné l'incrément et ajouté quelques bots wingmen pour donner un coup de pouce à ce bot ..
rancid_banana

Salut, j'espère que cela ne vous dérange pas, mais je préparais un banc de test avec toutes les soumissions actuelles et j'ai découvert que votre code retournait parfois des valeurs invalides au dernier tour, j'ai donc corrigé le bogue en réorganisant l'ordre quelques lignes. Désolé si j'ai changé quelque chose que vous n'auriez pas, n'hésitez pas à annuler les modifications et à corriger le bogue d'une autre manière!
Leo

@Leo: Pas de problème, merci de vous y intéresser.
rancid_banana

4

FiveFiveFive

Saute le premier tour et offre 555 $ pour les tours restants. Au dernier tour, tous les tapis seront allés à moins que 2 autres bots aient le même montant (et seront probablement à égalité).

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

Presque tout en

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

Offre toujours un peu moins que ce qu'elle a.


4

Escalade rapide

Offre des fractions croissantes de son argent à chaque tour (veuillez me faire savoir s'il y a des erreurs, un certain temps depuis que j'ai utilisé 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

Sous la moyenne

Similaire à la moyenne, mais va un peu plus bas

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

Ce joueur offre tout son argent moins le numéro du tour en cours, sauf au dernier tour, où il fait tapis.

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

Alterne entre une enchère sous son maximum et une mise à tapis.

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

J'ai pensé que je devais trouver quelque chose qui pourrait battre le moins_one de Steadybox. :)


4

Liste noire modulaire

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

Parie le montant le plus élevé possible qui n'est pas congru modulo 500 à tous les nombres qu'il a vu auparavant.

Modifié pour ne pas appliquer la liste noire lorsqu'il peut obtenir une victoire garantie.


Curieusement, il semble que la dernière mise à jour de votre autre bot affecte négativement ce bot. Actuellement, il blacklist_modest cinquième au classement , alors qu'il blacklistest à la deuxième place. Si l'ancienne version de blacklistest utilisée à la place, blacklisttombe à la sixième place, mais blacklist_mod prend la tête !
Steadybox

Le rejet blacklistcomplet semble donner blacklist_modune avance encore plus solide , mais ce n'est pas concluant.
Steadybox

Oh, merci, cela a du sens - ils sont proches du même algorithme au début sans l'ancienne logique de cas spécial, alors ils se marchent les uns les autres. Je pense que je vais juste supprimer le bot d'origine; Je ne vois pas de bonne raison de le garder.
histocrate

4

Heurist

L' Heurist traite ce jeu comme une probabilité répétable, il sait donc où tracer la ligne.

Il est également avare, il offre donc le strict minimum requis pour une victoire quand il le peut.

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

Avertissement: max_bidest sujet à changement


4

bob_hater

Ce bot n'aime pas Bob et va donc toujours miser 2 $ pour gagner contre Bob.

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

4

Frimer

C'est ce gars qui montre sa capacité mathématique dans des situations qui ne nécessitent vraiment rien de si compliqué. Jusqu'au dernier round (dans lequel il fait tapis), il utilise un modèle logistique pour déterminer son offre, plus si ses ennemis ont une plus grande partie de leur argent restant.

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 courbe logistique utilisée est f (x) = 1 / (1 + e -8 (x-0,5) ), où x est le rapport de l'argent ennemi actuel à l'argent ennemi potentiel total du round. Plus les autres en ont, plus il enchérit. Cela a l' avantage possible d'enchérir près de 500 $, mais pas tout à fait, au premier tour.


3

AntiMaxer

Faites correspondre le montant le plus élevé que nous pouvons nous permettre avec l'argent de tous les joueurs. Cela fera en sorte que tous les bots tentent de faire tapis sur ce round.

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

Presque la même chose que Patient Bot, mais pas en tant que patient. Obtient un score bien meilleur que lui, cependant.


3

Wingman 2

Si un ailier est bon, deux doivent être meilleurs?

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

Votre code ne fonctionnera pas car vous avez besoin d'une indentation pour le
contenu de

Fait intéressant, vos deux ailiers semblent battre votre bot d'origine (le lien pastebin contient le lien TIO, qui est trop long pour être publié dans un commentaire et même trop long pour les raccourcisseurs d'URL ...)
Steadybox

1
J'ai trouvé que les résultats étaient très sensibles à la réserve d'autres robots; des changements mineurs dans la valeur de l'incrément semblent avoir des résultats disproportionnés.
rancid_banana
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.