Jouons à Reaper - Fermé pour les soumissions

13

NOTE : Le gagnant de ce concours est Jack !!!. Aucune autre soumission ne sera acceptée.

Voici le salon de discussion pour ce défi du . Ceci est mon premier, donc je suis ouvert aux suggestions!

Reaper est un concept de jeu développé par l'Art de la résolution de problèmes qui implique de la patience et de la cupidité. Après avoir modifié le jeu pour l'adapter à un concours de style KOTH (Merci à @NathanMerrill et @dzaima pour vos suggestions et améliorations), voici le défi.

Le jeu fonctionne comme suit: nous avons une valeur connue sous le nom de Reap qui se multiplie par une constante donnée à chaque tick. Après chaque tick, chaque bot a l'option de "récolter", ce qui signifie ajouter la valeur actuelle de Reap à son score et réduire Reap à 1.

Cependant, il y a un nombre fixe de ticks qu'un bot doit attendre entre les "moissonnages", et un nombre fixe de points nécessaires pour gagner la partie.

Assez simple? Voici vos entrées:

E / S

Vous devez écrire une fonction en Python 3 qui prend 3 entrées. Le premier est selfutilisé pour référencer les objets de classe (illustré plus loin). Le second est le Reap, la valeur actuelle du Reap que vous gagneriez si vous "récoltiez". Le troisième est prevReapune liste des bots récoltés lors du tick précédent.

Autres objets auxquels vous pouvez accéder dans votre fonction:

self.obj: An object for your use to store information between ticks.
self.mult: The multiplier that Reap is multiplied by each tick
self.win: The score you need to win
self.points: Your current set of points
self.waittime: The amount of ticks that you must wait between reaps during the game
self.time: The number of ticks since your last reap
self.lenBots: The number of bots (including you) in the game.
self.getRandom(): Use to produce a random number between 0 and 1.

Vous NE DEVEZ pas modifier le contenu de ces objets, à l'exception de self.obj.

Vous devez sortir 1pour récolter, et toute autre chose (ou rien) pour ne pas récolter. Notez que si vous récoltez alors que vous n'avez pas attendu suffisamment de ticks, j'ignorerai le fait que vous avez choisi de récolter.

Règles

Les paramètres que je vais utiliser sont winning_score=10000, multiplier=1.6-(1.2/(1+sqrt(x))), waittime = floor(1.5*x)xest le nombre de bots dans le KOTH.

  • Le jeu se termine lorsqu'un joueur (ou plusieurs) atteint le score gagnant.
  • Lorsque plusieurs robots demandent à récolter à la fois, la priorité est donnée aux robots qui ont attendu plus longtemps (en cas d'égalité, les robots qui ont attendu le temps maximum sont tous autorisés à récolter et à gagner des points dans la récolte)
  • Votre bot ne doit pas prendre plus de 100 ms en moyenne sur 5 ticks.
  • Si vous souhaitez importer des bibliothèques, demandez! Je vais essayer d'ajouter toutes les bibliothèques que je peux exécuter sur ma version de bureau de Python (les mathématiques sont déjà importées: n'hésitez pas à l'utiliser)
  • Toutes les failles standard pour les KoTH, telles que les robots en double, les robots à une place, etc., sont également interdites.
  • Tous les bots qui utilisent n'importe quel type de hasard doivent utiliser la getRandomfonction que j'ai fournie.

Vous pouvez trouver le contrôleur dans le lien TIO ci-dessous. Pour l'utiliser, ajoutez le nom de votre fonction en BotListtant que chaîne, puis ajoutez la fonction au code. Modifier multiplierpour changer ce que la moisson est multipliée par chaque tick, modifier winning_scorepour changer le score nécessaire pour terminer le jeu et modifierwaittime pour changer le nombre de ticks à attendre entre les moissonnages.

Pour votre commodité, voici quelques exemples de robots (et plutôt idiots). La soumission de robots similaires à ceux-ci ne sera pas autorisée. Cependant, ils montrent comment fonctionne le contrôleur.

def Greedybot(self,Reap, prevReap):
    return 1
def Randombot(self,Reap, prevReap):
    if self.obj == None:
        self.obj=[]
    self.obj.append(prevReap)
    if self.getRandom()>0.5:
        return 1

Pour les personnes intéressées, voici le contrôleur avec les 15 soumissions intégrées: Essayez-le en ligne

RÉSULTATS FINAUX

WOO ILS SONT ENFIN ICI! Vérifiez le lien TIO ci-dessus pour voir quel code j'ai utilisé pour générer le classement final. Les résultats ne sont pas terriblement intéressants. Au cours des 1000 essais que j'ai effectués avec différentes graines aléatoires, les résultats ont été

1000 wins - Jack
0 wins - everyone else

Félicitations au gagnant du Bounty Jack !! (alias @Renzeee)

Don mille
la source
Disons que deux bots récoltent en même temps, et celui avec le temps d'attente le plus long gagne. L'autre bot aura-t-il également son temps d'attente activé malgré le fait qu'il n'a pas pu réellement récolter ce tour, gaspillant fondamentalement son «moisson»? Et que se passe-t-il lorsque deux bots récoltent en même temps, avec le même temps d'attente?
Kevin Cruijssen
1
Il est autorisé à utiliser len(BotList)?
Renzeee
1
@Renzeee Ooo n'y a pas pensé! Je ferai une modification rapide.
Don mille
1
@Renzeee Oh, c'est certainement quelque chose d'utile à considérer. Pourrait faire un deuxième bot similaire à mon Every 50, mais avec des calculs réels dans le bot lui-même, au lieu de ce que j'ai fait dans ma description en fonction des 25bots en jeu. Attendra d'abord un peu trop voir les robots des autres cependant. Rushabh Mehta , y aura-t-il une date limite / date finale lorsque tous les bots seront exécutés et qu'un gagnant sera déterminé?
Kevin Cruijssen
1
@Rushabh Mehta Gotcha, je m'abstiendrai. Je viens de demander à b / c que je suivais indépendamment les scores et les temps d'attente des autres bots afin de les sniper, et je suis paresseux. :)
Triggernométrie

Réponses:

9

Indécis Twitchy Mess

def mess(self, Reap, prevReap):
    if not hasattr(self.obj, "start"):
            self.obj.start = False
    if self.time < self.waittime:
        return 0
    if self.points + Reap >= self.win:
            return 1
    if Reap >= self.waittime / (self.lenBots + 2):
        self.obj.start = True
    if self.obj.start:
        return 1 if self.getRandom() > 0.2 else 0
    return 1 if self.getRandom() > 0.8 else 0

Ce bot effectue d'abord les vérifications habituelles (Puis-je récolter, puis-je gagner?), Puis recherche une valeur cible avant de récolter. Cependant, il est indécis, donc après avoir atteint l'objectif, il se demande combien de temps il peut attendre et ne récolte pas immédiatement. De plus, il est nerveux, il peut donc accidentellement "toucher le bouton" et récolter avant la cible.

Fait amusant: c'est essentiellement comme ça que je joue Reaper en tant qu'humain.

Quintec
la source
Joli bot +1. Je vais y regarder de plus près dans un instant. Rejoignez le chat si vous ne l'avez pas déjà fait
Don Thousand
@RushabhMehta Maintenant avec moins d'indécision; p
Quintec
J'ajouterai vos modifications quand je le pourrai!
Don Thousand
9

Tireur d'élite

Un bot alimenté par la rancune. Conserve les temps de recharge et les scores de l'adversaire. Tente d'empêcher les autres de gagner. Pratiquement jamais ne gagne, mais rend le jeu frustrant à jouer pour les autres.

ÉDITER:

  • Si récolter le ferait gagner, récoltez.
  • Si personne n'est> = 70% du score gagnant:

    • Si tout le monde est sur son temps de recharge, attendez le dernier moment possible pour récolter.
    • Si quelqu'un d'autre gagnerait en récoltant la valeur actuelle, et qu'ils sont actifs maintenant ou seraient actifs au prochain tour, récoltez.
    • Si au moins la moitié des autres utilisateurs sont sur leur temps de recharge, essayez de récolter. Cela rend difficile de cibler des adversaires spécifiques, et a donc été supprimé.
    • Sinon, récoltez 25% du temps (essentiellement pour garantir que ce bot récoltera PARFOIS, juste au cas où quelque chose de bizarre se produirait, comme tout le monde attend plusieurs tours).
  • Si quelqu'un EST> = 70% du score gagnant:

    • Si le tireur d'élite peut gagner un bris d'égalité et que le prochain tour serait supérieur à la valeur moyenne de récolte pour l'adversaire ayant le score le plus élevé, récolter
    • Si l'adversaire ayant le meilleur score quitte son temps de recharge au prochain tour, récoltez.
def Sniper(self, Reap, prevReap):
    # initialize opponents array
    if not hasattr(self.obj, "opponents"):
        self.obj.opponents = {}

    # initialize previous Reap value
    if not hasattr(self.obj, "lastReap"):
        self.obj.lastReap = 0

    # increment all stored wait times to see who will be "active" this turn
    for opponent in self.obj.opponents:
        self.obj.opponents[opponent]["time"] += 1

    # update opponents array
    for opponent in prevReap:
        # don't track yourself, since you're not an opponent
        if opponent != "Sniper":
            # initialize opponent
            if opponent not in self.obj.opponents:
                self.obj.opponents[opponent] = {"time": 0, "points": 0, "num_reaps": 0, "avg": 0}
            self.obj.opponents[opponent]["time"] = 0
            self.obj.opponents[opponent]["points"] += self.obj.lastReap
            self.obj.opponents[opponent]["num_reaps"] += 1
            self.obj.opponents[opponent]["avg"] = self.obj.opponents[opponent]["points"] / self.obj.opponents[opponent]["num_reaps"]

    # done "assigning" points for last round, update lastReap
    self.obj.lastReap = Reap

    # get current 1st place(s) (excluding yourself)
    winner = "" if len(self.obj.opponents) == 0 else max(self.obj.opponents, key=lambda opponent:self.obj.opponents[opponent]["points"])

    # you are ready now
    if self.time >= self.waittime:
        # current Reap is sufficient for you to win
        if self.points + Reap >= self.win:
            return 1

        if (
                # a 1st place exists
                winner != ''
                # if current 1st place is close to winning
                and self.obj.opponents[winner]["points"] / self.win >= .7
        ):
            if (
                    # next round's Reap value will be above opponent's average Reap
                    (Reap * self.mult >= self.obj.opponents[winner]["avg"])
                    # we have been waiting at least as long as our opponent (tiebreaker)
                    and self.time >= self.obj.opponents[winner]["time"]
            ):
                return 1

                # current 1st place opponent will be active next round
            if self.obj.opponents[winner]["time"] + 1 >= self.waittime:
                return 1

        else:
            if (
                    # everyone is waiting for their cooldown
                    all(values["time"] < self.waittime for key, values in self.obj.opponents.items())
                    # and we're tracking ALL opponents
                    and len(self.obj.opponents) == self.lenBots - 1
                    # at least one person will be ready next turn
                    and any(values["time"] + 1 >= self.waittime for key, values in self.obj.opponents.items())
            ):
                return 1

            if (
                    # opponent will be active next round
                    any( (values["time"] + 1 >= self.waittime)
                         # current Reap value would allow opponent to win
                         and (values["points"] + Reap >= self.win) for key, values in self.obj.opponents.items())
            ):
                return 1

            if (
                    # a 1st place exists
                    winner != ''
                    # current 1st place opponent will be active next round
                    and (self.obj.opponents[winner]["time"] + 1 >= self.waittime)
                    # next round's Reap value will be above their average Reap
                    and (Reap * self.mult >= self.obj.opponents[winner]["avg"])

            ):
                return 1

            # # at least half of opponents are waiting for their cooldown
            # if sum(values["time"] < self.waittime for key, values in self.obj.opponents.items()) >= (self.lenBots - 1) / 2:
            #     return 1

            # 25% of the time
            if self.getRandom() <= .25:
                return 1

    # default return: do not snipe
    return 0

Ennuyé

Juste pour le plaisir, ce bot a été amené par un ami et ne veut pas vraiment être ici. Ils lancent un d16 jusqu'à ce qu'ils obtiennent un nombre entre 1 et 9, puis ils tentent de récolter chaque fois qu'un nombre contient le chiffre choisi. (Aller chercher un d10 perturberait le jeu, ce qui est impoli, et 0 est tout simplement trop facile!)

def Bored(self, Reap, prevReap):
    # if this is the first round, determine your fav number
    if not hasattr(self.obj, "fav_int"):
        r = 0

        while r == 0:
            # 4 bits are required to code 1-9 (0b1001)
            for i in range(0, 4):
                # flip a coin. Puts a 1 in this bit place 50% of the time
                if self.getRandom() >= .50:
                    r += 2**i
            # if your random bit assigning has produced a number outside the range 1-9, try again
            if not (0 < r < 10):
                r = 0

        self.obj.fav_int = r

    # you are ready now
    if self.time >= self.waittime:
        # current Reap is sufficient for you to win
        if self.points + Reap >= self.win:
            return 1
        # do you like this value?
        if str(self.obj.fav_int) in str(Reap):
            return 1
        # do you like your wait time?
        if self.time % int(self.obj.fav_int) == 0:
            return 1

    # default return: do not reap
    return 0
Triggernométrie
la source
Joli bot! +1. Ce sera intéressant de voir comment cela fonctionne.
Don Thousand
1
Je pense que vous devriez utiliser self.obj.opponents[opponent]["time"] += 1dans la première boucle for et self.obj.lastReapà la fin de la seconde boucle for. A part ça, de belles idées. Je suis curieux de voir comment cela fonctionnerait contre beaucoup d'autres robots. Lorsque j'utilise beaucoup de robots gourmands et aléatoires, ils récolteront simplement dès que possible car la plupart du temps, la moitié des robots ne peuvent pas récolter. Mais bien sûr, ce ne sont pas des concurrents réalistes.
Renzeee
@Triggernometry Vous devez rejoindre le chat. Vérifiez également les modifications que j'ai publiées. Veuillez vous assurer que les modifications que j'ai apportées à votre bot sont correctes.
Don Thousand
7

Jack

Ceci est un bot simple avec 4 règles:

  • Ne récoltez pas quand il ne fait rien
  • Toujours récolter quand récolter nous permet de gagner
  • Récolter également lorsqu'il n'y a pas eu de récolte pour 3 ticks
  • Sinon, ne fais rien

J'ai optimisé les 3 ticks par rapport aux robots existants (Sniper, grim_reaper, Every50, mess, BetterRandom, Averager, un peu plus).

def Jack(self, Reap, prevReap):
    if self.time < self.waittime:
        return 0
    if self.win - self.points < Reap:
        return 1
    if self.mult ** 3 <= Reap:
        return 1
    return 0

J'ai essayé de conserver mon ancienne solution (5 ticks) mais aussi de récolter si vous n'avez pas récolté plus de X ticks, puis de récolter après que moins de ticks ont été passés pendant la non-récolte (c'est-à-dire 5, si vous avez attendu plus longtemps que vous-même) .waittime + 5, récolter également s'il n'a pas été récolté pendant 4 ticks). Mais cela ne s'est pas amélioré juste en récoltant toujours après 4 ticks au lieu de 5.

Renzeee
la source
5

Tous les 50

Ces bots récolteront chaque fois que le Reapmontant est supérieur à 50.

Pourquoi 50?

Si je fais l'hypothèse qu'il y aura 25 bots en jeu, cela signifie le multiplier = 1.6-(1.2/(1+sqrt(25))) = 1.4et le waittime = floor(1.5*25) = 37. Depuis le Reapdébut à 1, il montera comme ceci:

Round: 1  2    3     4      5      6      7      8       9       10      11      12      13      14      15       16       17       18       19       20       etc.
Reap:  1  1.4  1.96  2.744  ~3.84  ~5.39  ~7.53  ~10.54  ~14.76  ~20.66  ~28.92  ~40.50  ~56.69  ~79.37  ~111.12  ~155.57  ~217.79  ~304.91  ~426.88  ~597.63  etc.

Comme vous pouvez le voir, il atteint plus de 50 après 13 ticks. Depuis la Reapreplacerez à 1 chaque fois qu'un moissonne bot, et waittimepour un bot qui moissonne est 37, la probabilité d' un bot moissonne plus tôt que plus tard est assez élevé, en particulier avec des bots similaires à l'exemple GreedyBot, qui récoltera dès que leur waittimeest - à nouveau disponible. Au début, je voulais faire 200, ce qui est le 17ème tick, un peu au milieu des 37 ticks du temps d'attente, mais avec l'hypothèse qu'il y a 25 bots en jeu, il y a de fortes chances que quelqu'un d'autre arrache Reapavant moi. Je l'ai donc abaissé à 50. C'est toujours un bon chiffre arrondi, mais surtout parce que c'est le 13ème tick (avec 25 bots), et 13 et "récolter" correspondent également un peu à ce même genre "diabolique".

Code:

Le code est risible trivial ..

def Every50(self, Reap, prevReap):
  return int(Reap > 50)

Remarques:

Ce bot est assez mauvais avec une faible quantité de bots en jeu. Pour l'instant je vais le laisser, et je pourrais faire un meilleur bot calculant en fait le meilleur moment pour Reap. Avec une quantité extrêmement faible de bots en jeu, la valeur waittimeest également beaucoup plus faible, donc même GreedyBotpourrait gagner assez facilement de ce bot si lewaittime est suffisamment basse.

Espérons que plus de gens ajouteront beaucoup plus de bots. ; p

Kevin Cruijssen
la source
def Every49(self, Reap, prevReap): return Reap > 49 Votre déménagement.
Quintec
@Quintec Hehe. Avec 25 bots en jeu, cela signifierait que c'est toujours le 13ème tick et que nous gagnons tous les deux la moisson, donc cela ne me dérange pas de partager la victoire avec vous, lol. ; p
Kevin Cruijssen
Vous voudrez peut-être intcontourner l'inégalité, car 1 est le vrai commandement
Don Thousand
@Quintec, je suis au courant de votre blague, mais je n'autoriserai pas les bots 1-up ou en double
Don Thousand
@RushabhMehta Je ne programme pas très souvent en Python, donc je doutais déjà si je devais ajouter la distribution pour rendre l' Truean explicite 1. J'ai pensé que le True == 1chèque reviendrait toujours Truepour mon bot en l'ajoutant aux listes de Reapersvotre nextfonction, mais j'ai quand même ajouté le cast à int comme vous l'avez suggéré.
Kevin Cruijssen
5

Averager

def Averager(self,Reap,prevReap):
    returner = 0
    if not hasattr(self.obj,"last"):
        self.obj.last = Reap
        self.obj.total = 0
        self.obj.count = 0
        returner = 1
    else:
        if len(prevReap) > 0:
            self.obj.total += self.obj.last
            self.obj.count += 1
        self.obj.last = Reap
    if self.obj.count > 0 and Reap > self.obj.total / self.obj.count:
        returner = 1
    return returner

Ce bot essaie de récolter chaque fois que la valeur de récolte actuelle est supérieure à la valeur de récolte moyenne.

Jo.
la source
Très joli bot! +1
Don Thousand
Je suis à la fois extrêmement ennuyé et impressionné qu'un algorithme aussi simple bat tout le monde si facilement. Bon travail!
Triggernométrie
3

Faucheuse

Ce bot conserve une moyenne courante des valeurs de toutes les moissonnages précédents ainsi que le temps d'attente de chaque bot. Il récolte quand il a attendu plus de 3/4 des autres robots et que la moisson est au moins 3/4 de la taille de la moisson moyenne vue jusqu'à présent. L'objectif est de saisir un grand nombre de moissons de taille raisonnable et à faible risque.

def grim_reaper(self, Reap, prevReap):
    if self.obj == None:
        self.obj = {}
        self.obj["reaps"] = []
        self.obj["prev"] = 1
        self.obj["players"] = {i:0 for i in range(math.ceil(self.waittime / 1.5))}
    if Reap == 1 and len(prevReap) > 0:
        self.obj["reaps"].append(self.obj["prev"])
        for player in prevReap:
            self.obj["players"][player] = 0

    retvalue = 0
    if (len(self.obj["reaps"]) > 0 
         and Reap > sum(self.obj["reaps"]) / len(self.obj["reaps"]) * 3. / 4.
         and sum([self.time >= i for i in self.obj["players"].values()]) >= len(self.obj["players"].values()) * 3 / 4):
        retvalue = 1

    for player in self.obj["players"]:
        self.obj["players"][player] += 1
    self.obj["prev"] = Reap
    return retvalue

Modifier: correction de quelques erreurs de syntaxe embarrassantes.

Essayez-le en ligne

Coton Zachary
la source
1
Vous devez utiliser self.obj.reapsau lieu de self.reapset self.objau lieu de self.objectet prevReapau lieu de prevLeapet ajouter () après self.obj.players.valuesdeux fois. Et je pense que ça self.obj.reaps = []ne marchera que si self.objc'est un objet. Je ne suis pas complètement sûr que tout fonctionne toujours comme prévu et si tout ce que j'ai dit est vrai, mais après ces changements et l'utilisation d'un objet factice pour self.objquand il n'existe pas encore, votre code compile pour moi.
Renzeee
@ZacharyColton Vous n'avez pas besoin d'importer les mathématiques. Il est déjà importé
Don Thousand
@RushabhMehta J'ai ajouté class Object(object):[nouvelle ligne] passen haut et utilisé self.obj = Object()dans le if not hasattr(..)(si je me souviens bien).
Renzeee
@Renzeee aha ic
Don Thousand
@ZacharyCotton Vous devez rejoindre le chat.
Don Thousand
3

BetterRandom

def BetterRandom(self,reap,prevReap):
    return self.getRandom()>(reap/self.mult**self.waittime)**-0.810192835

Le bot est basé sur l'hypothèse que la chance de récolter doit être proportionnelle à la taille de la récolte car un point est un point, peu importe quand il est obtenu. Il y a toujours une très petite chance de récolter, cela maintient le comportement exploitable. J'ai d'abord pensé que ce serait directement proportionnel et j'ai supposé que la constante de proportionnalité était autour,1/mult^waittime (la récolte maximale en supposant qu'au moins un bot joue gourmand) après avoir exécuté quelques simulations, j'ai trouvé que c'était en effet la constante optimale. Mais le bot était toujours surperformé par Random, j'ai donc conclu que la relation n'était pas directement proportionnelle et j'ai ajouté une constante pour calculer la relation. Après quelques simulations, j'ai trouvé que mon test de bots -1.5était optimal. Cela correspond en fait à une relation inversement proportionnelle entre la chance de récolte etreap*sqrt(reap)ce qui est surprenant. Je soupçonne donc que cela dépend fortement des bots spécifiques, donc une version de ce bot qui calcule k tout en jouant serait mieux. (Mais je ne sais pas si vous êtes autorisé à utiliser les données des tours précédents).

EDIT: J'ai fait un programme pour trouver automatiquement le type de proportionnalité. Sur l'ensemble de test, ["myBot("+str(k)+")","Randombot","Greedybot","Every50","Jack","grim_reaper","Averager","mess"]j'ai trouvé la nouvelle valeur.

fejfo
la source
j'ajouterai bientôt de nouvelles statistiques en utilisant votre bot
Don Thousand
1
Il semble être (reap/self.mult**self.waittime)**-0.810192835toujours supérieur à 1, c'est-à-dire que self.getRandom () n'est jamais plus élevé.
Renzeee
@fejfo vous êtes également autorisé à utiliser les données des tours précédents. C'est pour ça self.obj. Pour voir quelques exemples sur la façon de l'utiliser, regardez quelques autres robots qui l'utilisent.
Don Thousand
3

Cible

def target(self,Reap,prevReap):
    if not hasattr(self.obj, "target_time"):
        self.obj.target_time = -1
        self.obj.targeting = False
        self.obj.target = None
    if self.obj.target_time >= 0:
        self.obj.target_time += 1

    if self.time < self.waittime:
            return 0
    if self.points + Reap >= self.win:
        return 1
    if len(prevReap) > 0:
        if not self.obj.targeting:
            self.obj.target_time = 0
            self.obj.target = prevReap[int(self.getRandom() * len(prevReap))]
            self.obj.targeting = True
    if self.waittime <= self.obj.target_time + 1:
        self.obj.targeting = False
        self.obj.target = None
        self.obj.target_time = -1
        return 1
    return 0

Mes chances de gagner avec le mess sont presque nulles maintenant, alors il est temps de gâcher tous les autres bots de autant de façons que possible! :)

Ce bot fonctionne de manière similaire au tireur d'élite. Chaque fois que quelqu'un récolte, il choisit une cible aléatoire parmi ceux qui récoltent. Ensuite, il attend simplement que cette cible puisse à nouveau récolter et la snipe. Cependant, cela ne change pas de focus - une fois que vous avez été choisi et verrouillé, vous ne pouvez pas vous échapper :)

Quintec
la source
2

EveryN

Je suppose qu'il est temps pour mon deuxième bot juste avant la date limite.

Ce bot va:

  • Passer quand il est encore dans son temps d'attente pour la dernière moisson
  • Récoltez quand il peut gagner
  • Moissonner quand personne n'a moissonné pendant au moins les ntours, où nest calculé avecn = 3 + ceil(self.waittime / self.lenBots)

Code:

def every_n(self, Reap, prevReap):
    # Initialize obj fields
    if not hasattr(self.obj, "roundsWithoutReaps"):
        self.obj.roundsWithoutReaps = 0

    # Increase the roundsWithoutReaps if no bots reaped last round
    if len(prevReap) < 1:
        self.obj.roundsWithoutReaps += 1
    else
        self.obj.roundsWithoutReaps = 0

    # Skip if you're still in your waiting time
    if self.time < self.waittime:
        return 0
    # Reap if you can win
    if self.win - self.points < Reap:
        return 1

    # i.e. 25 bots: 3 + ceil(37 / 25) = 5
    n = 3 + math.ceil(self.waittime / self.lenBots)

    # Only reap when no bots have reaped for at least `n` rounds
    if self.obj.roundsWithoutReaps >= n:
        self.obj.roundsWithoutReaps = 0
        return 1

    return 0

Je ne programme pas très souvent en Python, donc si vous voyez des erreurs faites le moi savoir.

Kevin Cruijssen
la source
Nom de la variable longue sacrée. (Aussi, PEP: python.org/dev/peps/pep-0008 )
Quintec
@Quintec Changé l'indentation de 2 espaces à 4; raccourci le subsequentRoundsWithoutReapsto roundsWithoutReaps; utilisé en minuscules avec des traits de soulignement pour le nom de la méthode; et supprimé les parenthèses au niveau des instructions if. Merci.
Kevin Cruijssen
Aucun problème! (Techniquement, cela devrait être rounds_without_reaps, mais ce n'est pas vraiment un problème car ce défi utilise également mixedCamelCase donc cela n'a pas vraiment d'importance)
Quintec
@Quintec Ah ok. J'ai regardé les variables prevReapet lenBotset telles et supposées sont camelCase comme en Java. ;) Ah bien, quel que soit le cas que nous utilisons, cela devrait quand même fonctionner. Les 2 au lieu de 4 espaces en retrait auraient probablement causé quelques problèmes, alors merci dans les deux cas.
Kevin Cruijssen
2

En cours: mon projet d'étendre T4T à chaque KOTH ouvert.

Mésange pour Tat

def t4t(self, r, p):
    if(not hasattr(self.obj,"last")): self.obj.last = self.win
    if(p):
        self.obj.last = r
        return 0

    # The usual checks
    if self.time < self.waittime:
        return 0
    if self.points + r >= self.win:
        return 1

    if(r >= self.obj.last):
        return 1

Mésange pour n Tats

def t4nt(self, r, p):
    n = 5 # Subject to change
    if(not hasattr(self.obj,"last")): self.obj.last = [self.win]*n

    if(p):
        self.obj.last.append(r)
        self.obj.last.pop(0)
        return 0

    # The usual checks
    if(self.time < self.waittime):
        return 0
    if(self.points + r >= self.win):
        return 1

    if(r >= self.obj.last[0]):
        return 1

Kevin

Juste pour vous garder sur vos orteils.

def kevin(just, a, joke):
    return 0
SIGSTACKFAULT
la source
Assurez-vous de vous souvenir, ce self.lastn'est pas une chose, mais vous pouvez en faire self.obj.lastune chose !. Quoi qu'il en soit, je vais ajouter vos trois bots pour les mèmes +1
Don Thousand
Ouais, je suis un idiot. Fixé.
SIGSTACKFAULT
@RushabhMehta Je viens de passer en revue et de les faire fonctionner. pls modifier.
SIGSTACKFAULT
ça m'a l'air bien! Rejoignez le GC, j'y posterai des résultats partiels
Don Thousand
1

Moyenne Joe

Je me suis inspiré de Averager et j'ai créé un bot qui calcule en moyenne le nombre de tours qu'il faut avant que quelqu'un ne récolte et essaie de récolter un tour avant cela.

def average_joe(self, Reap, prevReap):

    if not hasattr(self.obj, "average_turns"):
        self.obj.turns_since_reap = 1
        self.obj.total_turns = 0
        self.obj.total_reaps = 0
        return 1

    if len(prevReap) > 0:
        self.obj.total_turns = self.obj.total_turns + self.obj.turns_since_reap
        self.obj.total_reaps += 1
        self.obj.turns_since_reap = 0
    else:
        self.obj.turns_since_reap += 1

    # Don't reap if you are in cooldown
    if self.time < self.waittime:
        return 0

    # Reap if you are going to win
    if self.win - self.points < Reap:
        return 1

    # Reap if it is one turn before average
    average_turns = self.obj.total_turns / self.obj.total_reaps

    if average_turns - 1 >= self.obj.turns_since_reap:
        return 1
    else:
        return 0
DobromirM
la source
J'ajouterai ça demain.
Don Thousand
1

HardCoded

Oui, ça l'est.

def HardCo(self,reap,prevReap):
    return reap > 2

Au lieu de faire la moyenne sur les moissonnages passés, utilisez une moyenne pré-calculée sur une course typique. Cela ne s'améliorera pas avec le temps de toute façon.

GB
la source