Créez un bot pour choisir le plus petit numéro unique.
(Basé sur une expérience de psychologie dont j'ai entendu parler il y a de nombreuses années mais que je n'ai pas pu retrouver.)
Règles
- Chaque jeu sera composé de 10 bots sélectionnés au hasard jouant 1000 tours.
- Chaque tour, tous les bots sélectionnent un entier de 1 à 10 (inclus). Tous les bots qui choisissent la même valeur seront exclus et le bot restant avec la plus petite valeur recevra un point.
- Dans le cas où aucun bot ne choisit une valeur unique, aucun point ne sera attribué.
- À la fin de 1000 tours, le bot avec le plus de points (ou tous les bots à égalité avec le plus de points) remporte la partie.
- Le tournoi durera 200 * (nombre de joueurs) matchs.
- Le bot avec le pourcentage de victoire le plus élevé remporte le tournoi.
Caractéristiques
Les bots doivent être des classes Python 3 et doivent implémenter deux méthodes: select
et update
.
Les bots seront construits avec un index.
select
ne reçoit aucun argument et renvoie le choix du bot pour le tour en cours.
update
est passé une liste des choix effectués par chaque bot au tour précédent.
Exemple
class Lowball(object):
def __init__(self, index):
# Initial setup happens here.
self.index = index
def select(self):
# Decision-making happens here.
return 1
def update(self, choices):
# Learning about opponents happens here.
# Note that choices[self.index] will be this bot's choice.
pass
Manette
import numpy as np
from bots import allBotConstructors
allIndices = range(len(allBotConstructors))
games = {i: 0 for i in allIndices}
wins = {i: 0 for i in allIndices}
for _ in range(200 * len(allBotConstructors)):
# Choose players.
playerIndices = np.random.choice(allIndices, 10, replace=False)
players = [allBotConstructors[j](i) for i, j in enumerate(playerIndices)]
scores = [0] * 10
for _ in range(1000):
# Let everyone choose a value.
choices = [bot.select() for bot in players]
for bot in players:
bot.update(choices[:])
# Find who picked the best.
unique = [x for x in choices if choices.count(x) == 1]
if unique:
scores[choices.index(min(unique))] += 1
# Update stats.
for i in playerIndices:
games[i] += 1
bestScore = max(scores)
for i, s in enumerate(scores):
if s == bestScore:
wins[playerIndices[i]] += 1
winRates = {i: wins[i] / games[i] for i in allIndices}
for i in sorted(winRates, key=lambda i: winRates[i], reverse=True):
print('{:>40}: {:.4f} ({}/{})'.format(allBotConstructors[i], winRates[i], wins[i], games[i]))
Information additionnelle
- Aucun bot ne jouera dans un match contre lui-même.
- Dans le cas peu probable où un bot est inclus dans moins de 100 matchs, le tournoi sera relancé.
- Les bots peuvent stocker l'état entre les tours, mais pas entre les jeux.
- L'accès au contrôleur ou à d'autres robots n'est pas autorisé.
- Le nombre de parties et le nombre de tours par partie sont susceptibles d'augmenter si les résultats sont trop variables.
- Tous les bots qui soulèvent des erreurs ou donnent des réponses invalides (non-ints, valeurs en dehors de [1, 10], etc.) seront disqualifiés et le tournoi sera relancé sans eux.
- Il n'y a pas de limite de temps pour les tours, mais je peux en appliquer un si les bots prennent trop de temps pour réfléchir.
- Il n'y a pas de limite au nombre de soumissions par utilisateur.
La date limite pour les soumissions est 23:59:59 UTC le vendredi 28 septembre.Le tournoi est maintenant fermé pour les soumissions.
Résultats
BayesBot: 0.3998 (796/1991)
WhoopDiScoopDiPoop: 0.3913 (752/1922)
PoopDiScoopty: 0.3216 (649/2018)
Water: 0.3213 (660/2054)
Lowball: 0.2743 (564/2056)
Saboteur: 0.2730 (553/2026)
OneUpper: 0.2640 (532/2015)
StupidGreedyOne: 0.2610 (516/1977)
SecondSaboteur: 0.2492 (492/1974)
T42T: 0.2407 (488/2027)
T4T: 0.2368 (476/2010)
OpportunityBot: 0.2322 (454/1955)
TheGeneral: 0.1932 (374/1936)
FindRepeats: 0.1433 (280/1954)
MinWin: 0.1398 (283/2025)
LazyStalker: 0.1130 (226/2000)
FollowBot: 0.1112 (229/2060)
Assassin: 0.1096 (219/1999)
MostlyAverage: 0.0958 (194/2024)
UnchosenBot: 0.0890 (174/1955)
Raccoon: 0.0868 (175/2015)
Equalizer: 0.0831 (166/1997)
AvoidConstantBots: 0.0798 (158/1980)
WeightedPreviousUnchosen: 0.0599 (122/2038)
BitterBot: 0.0581 (116/1996)
Profiteur: 0.0564 (114/2023)
HistoryBot: 0.0425 (84/1978)
ThreeFourSix: 0.0328 (65/1984)
Stalker: 0.0306 (61/1994)
Psychadelic: 0.0278 (54/1943)
Unpopulist: 0.0186 (37/1994)
PoissonsBot: 0.0177 (35/1978)
RaccoonTriangle: 0.0168 (33/1964)
LowHalfRNG: 0.0134 (27/2022)
VictoryPM1: 0.0109 (22/2016)
TimeWeighted: 0.0079 (16/2021)
TotallyLost: 0.0077 (15/1945)
OneTrackMind: 0.0065 (13/1985)
LuckySeven: 0.0053 (11/2063)
FinalCountdown: 0.0045 (9/2000)
Triangle: 0.0039 (8/2052)
LeastFrequent: 0.0019 (4/2067)
Fountain: 0.0015 (3/1951)
PlayerCycle: 0.0015 (3/1995)
Cycler: 0.0010 (2/1986)
SecureRNG: 0.0010 (2/2032)
SneakyNiner: 0.0005 (1/2030)
I_Like_Nines: 0.0000 (0/1973)
bots.py
dans le même répertoire contenant tous les bots. À la fin, créez une liste des constructeurs:allBotConstructors = [Lowball, BayesBot, ...]
Réponses:
BayesBot
Tente de faire le choix optimal à l'aide d'un modèle statistique simple.
la source
Évitez les robots constants
Gardez une trace des robots qui ont toujours renvoyé la même valeur et ignorez ces valeurs. Parmi les valeurs restantes, sélectionnez-les au hasard, mais biaisez de manière significative vers des valeurs plus faibles.
la source
WaitWhatBot
Pas le bot le plus compétitif et certainement pas GTO , mais étouffera le score de tout adversaire "toujours 1" ou "presque toujours 1" dans le même jeu que dans un tel scénario WaitWhatBot devient aussi un tel bot.
Utilise des probabilités évolutives avec des poids pondérés à la fois dans le temps (plus récent -> plus grand poids) et dans la valeur de choix (point inférieur -> plus grand poids).
Utilise du code quelque peu obscurci pour un petit fou rire.
la source
Stalker
Au début du jeu, ce bot choisit au hasard un index spécifique comme cible. Il traque ensuite tout le jeu, en copiant le numéro choisi au tour précédent.
la source
Stupid Greedy One
Ce bot suppose que les autres bots ne veulent pas égaler.
Je me rends compte que c'est la même chose que l'exemple fourni, mais j'ai pensé avant de lire jusque-là. Si cela ne correspond pas à la façon dont les défis KoTH sont gérés, faites-le moi savoir.
la source
self.index
.HistoryBot
Implémentation du commentaire de user2390246:
la source
OneUpper
Les robots de tous les autres visent soit 1 ou au hasard, alors pourquoi ne pas viser seulement 2?
la source
Débit comme l'eau
Évite les algorithmes de base de détection de bots constants en doublant sur chaque nombre, progressant lentement vers des valeurs plus faibles s'ils ne sont pas occupés.
la source
Complètement perdu
la source
Le compte à rebours final
Essayez-le en ligne!
Renvoie 10 pour les 100 premiers tours, 9 pour les 100 suivants et ainsi de suite.
la source
Opportunitybot
Ce bot garde une trace du plus petit nombre non choisi par les autres bots à chaque tour (le plus petit nombre disponible ou opportunité), et joue le nombre qui a été ce nombre le plus fréquemment.
la source
PatterMatcher
Recherche les sections répétitives dans les soumissions des robots, essaie de prévoir et d'éviter les nombres.
Triangle
La chance de choisir n est
(10-n)/45
TimeWeighted
La probabilité qu'un bot choisisse un nombre est proportionnelle à
(10-n)*Δt
. Le premier tour est identique au triangle.Moins fréquent
Soumet le nombre le moins fréquent, s'il est égal, prendre le plus bas.
Le plus longtemps
Identique à la fréquence mais avec le plus long délai entre les soumissions.
Saboteur
Soumet le numéro le plus bas qui a été soumis la dernière fois.
SecondSaboteur
Soumet le deuxième numéro le plus bas qui a été soumis la dernière fois
Profiteur
Soumet le plus petit nombre non soumis la dernière fois
Désolé, je me suis un peu emporté, j'ai eu l'idée de nouveaux robots lors de la mise en œuvre de la précédente. Je ne savais pas lequel serait le meilleur et je suis curieux de connaître les performances de chacun d'eux. Vous pouvez tous les trouver ici: https://repl.it/@Fejfo/Lowest-Unique-Number
la source
set(range(10)
.Le top 50% RNG bot
J'étais sur le point de poster un bot aléatoire, mais hidefromkgb a posté avant moi (en postant, ils se font une cible facile pour le KGB, pas un bon moyen de se cacher). Ceci est ma première réponse KOTH, espérant juste battre le bot rng.
la source
Le cycliste
Ce bot passe simplement en revue chacun des nombres à son tour. Pour le plaisir, il initialise le compteur avec son index.
la source
OneTrackMind
Ce bot choisit un nombre au hasard et s'en tient à lui pendant 50 tours, puis en choisit un autre et répète.
la source
Sept chanceux
J'ai de la chance aujourd'hui! Je jette tout sur 7!
la source
Mon idée est que la stratégie dépend plus du nombre de robots que de l'évaluation réelle des stratégies.
Avec un nombre important de bots, les options sont:
Robots "gourmands" visant les numéros 1-3 inférieurs 10 robots étant "intelligents" et visant à obtenir les numéros 1-3 inférieurs, le mieux est de laisser ces robots interférer entre eux.
Les robots "intelligents" qui, une fois qu'ils se rendent compte que 4 est toujours ramassé, iront ailleurs.
Robots "aléatoires" et "constants". Pas grand chose à faire ici.
Donc, je parie sur # 4.
la source
L'essentiel du robot RNG
la source
Assassin
Reste dans l'ombre, puis vise la supposition la plus basse actuelle. Courir.
la source
FollowBot
Copiez le gagnant du dernier tour, ou au moins la meilleure sélection à égalité minimale s'il n'y avait pas de gagnant.
la source
Psychadelic
La seule façon de gagner une guerre nucléaire est de devenir fou. Je vais donc rendre fou tous les bots prédictifs du tournoi.
la source
UnchosenBot
Prend les choix du dernier tour et choisit le plus petit nombre non choisi (en ignorant le choix de UnchosenBot, bien sûr).
la source
Whoop-di-scoop-di-poop
Merde-di-scoopty
Je n'ai jamais vu ni touché Python, est-ce impythonique?
la source
<!-- language: lang-python -->
avant le bloc de code pour activer la coloration syntaxiquepython
étiquette sur la question et j'ai pensé que ce serait automatique mais j'ai écrit quelque chose de mauvais.others = [c for i, c in enumerate(choices) if i != self.index]
, ou, car par la suite vous n'utilisez cette variable que pour les tests d'appartenance,{ }
plutôt que de[ ]
construire unset
plutôt qu'unlist
.if (self.guess)
est également très impythonique.self.guess
sont entrés là-dedans! Doit être l'un des formateurs.Fontaine
Un simple bot choisit le numéro le plus bas en premier et si un autre bot le choisit aussi, il incrémentera le compteur - le sol se remplit et l'eau coule. Quand il atteint 11, il redémarre à 1 - l'eau est pompée vers le haut.
la source
target
à 10?PoissonsBot
Sélectionnez des nombres à partir d'une distribution de Poisson qui est biaisée à des valeurs inférieures. Ajustez le paramètre moyen de la distribution vers le haut si nous sommes à égalité et vers le bas s'il y a des suppositions en dessous de nous. La taille des pas diminue progressivement au fur et à mesure que le jeu avance.
la source
MinWin
Conserve un décompte en cours des valeurs gagnantes et des valeurs minimales non sélectionnées (où la valeur minimale non sélectionnée n'est prise en compte que si elle est inférieure à la valeur gagnante). Il sélectionne au hasard parmi ces valeurs gagnantes et minimales.
la source
PlayerCycle
Parcourt les joueurs. Le choix du joueur actuel (pourrait être lui-même) est maintenant le choix de ce bot. Démarre l'impression 8, car pourquoi pas. Désolé, je ne peux pas python, c'est probablement du mauvais code.
Edit: Merci à Triggernometry pour l'amélioration de mon code avec itertools
la source
Raton laveur
Choisissez le numéro le plus bas non choisi lors du tour précédent, à l'exception de notre propre choix précédent, qui pourrait être choisi à nouveau cette fois. Au premier tour, choisissez 1. (Étant donné 9 adversaires et 10 choix, il est garanti qu'il y a une valeur disponible.)
J'ai trouvé cela indépendamment, mais je vois maintenant au moins 2 robots précédents qui sont essentiellement les mêmes.
Triangle de raton laveur
Combine raton laveur et triangle: parmi les valeurs non choisies, choisissez-en une en fonction de la probabilité du triangle inversé.
la source
AttributeError: 'RaccoonTriangle' object has no attribute 'boundaries'
Le général
Le général se bat toujours la dernière guerre (s) .
la source
Pas de répétition aléatoire
Bot choisit au hasard, mais évite de choisir le même numéro que lors du tour précédent.
la source