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 roi de la colline . 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 self
utilisé 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 prevReap
une 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 1
pour 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)
où x
est 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
getRandom
fonction 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 BotList
tant que chaîne, puis ajoutez la fonction au code. Modifier multiplier
pour changer ce que la moisson est multipliée par chaque tick, modifier winning_score
pour 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)
la source
len(BotList)
?25
bots 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é?Réponses:
Indécis Twitchy Mess
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.
la source
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 personne n'est> = 70% du score gagnant:
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é.Si quelqu'un EST> = 70% du score gagnant:
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!)
la source
self.obj.opponents[opponent]["time"] += 1
dans la première boucle for etself.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.Jack
Ceci est un bot simple avec 4 règles:
J'ai optimisé les 3 ticks par rapport aux robots existants (Sniper, grim_reaper, Every50, mess, BetterRandom, Averager, un peu plus).
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.
la source
Tous les 50
Ces bots récolteront chaque fois que le
Reap
montant 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.4
et lewaittime = floor(1.5*25) = 37
. Depuis leReap
début à1
, il montera comme ceci:Comme vous pouvez le voir, il atteint plus de 50 après 13 ticks. Depuis la
Reap
replacerez à 1 chaque fois qu'un moissonne bot, etwaittime
pour 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'exempleGreedyBot
, qui récoltera dès que leurwaittime
est - à 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 arracheReap
avant 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 ..
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 valeurwaittime
est également beaucoup plus faible, donc mêmeGreedyBot
pourrait gagner assez facilement de ce bot si lewaittime
est suffisamment basse.Espérons que plus de gens ajouteront beaucoup plus de bots. ; p
la source
def Every49(self, Reap, prevReap): return Reap > 49
Votre déménagement.int
contourner l'inégalité, car 1 est le vrai commandementTrue
an explicite1
. J'ai pensé que leTrue == 1
chèque reviendrait toujoursTrue
pour mon bot en l'ajoutant aux listes deReapers
votrenext
fonction, mais j'ai quand même ajouté le cast à int comme vous l'avez suggéré.Averager
Ce bot essaie de récolter chaque fois que la valeur de récolte actuelle est supérieure à la valeur de récolte moyenne.
la source
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.
Modifier: correction de quelques erreurs de syntaxe embarrassantes.
Essayez-le en ligne
la source
self.obj.reaps
au lieu deself.reaps
etself.obj
au lieu deself.object
etprevReap
au lieu deprevLeap
et ajouter () aprèsself.obj.players.values
deux fois. Et je pense que çaself.obj.reaps = []
ne marchera que siself.obj
c'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 pourself.obj
quand il n'existe pas encore, votre code compile pour moi.class Object(object):
[nouvelle ligne]pass
en haut et utiliséself.obj = Object()
dans leif not hasattr(..)
(si je me souviens bien).BetterRandom
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.la source
(reap/self.mult**self.waittime)**-0.810192835
toujours supérieur à 1, c'est-à-dire que self.getRandom () n'est jamais plus élevé.self.obj
. Pour voir quelques exemples sur la façon de l'utiliser, regardez quelques autres robots qui l'utilisent.Cible
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 :)
la source
EveryN
Je suppose qu'il est temps pour mon deuxième bot juste avant la date limite.
Ce bot va:
n
tours, oùn
est calculé avecn = 3 + ceil(self.waittime / self.lenBots)
Code:
Je ne programme pas très souvent en Python, donc si vous voyez des erreurs faites le moi savoir.
la source
subsequentRoundsWithoutReaps
toroundsWithoutReaps
; 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.prevReap
etlenBots
et 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.En cours: mon projet d'étendre T4T à chaque KOTH ouvert.
Mésange pour Tat
Mésange pour n Tats
Kevin
Juste pour vous garder sur vos orteils.
la source
self.last
n'est pas une chose, mais vous pouvez en faireself.obj.last
une chose !. Quoi qu'il en soit, je vais ajouter vos trois bots pour les mèmes +1Moyenne 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.
la source
HardCoded
Oui, ça l'est.
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.
la source