ÉTAT DU DÉFI: OUVERT
Commentez, ouvrez un PR ou criez-moi si je manque votre bot.
Le dilemme du prisonnier ... avec trois choix. Fou, hein?
Voici notre matrice de gains. Joueur A à gauche, B en haut
A,B| C | N | D
---|---|---|---
C |3,3|4,1|0,5
N |1,4|2,2|3,2
D |5,0|2,3|1,1
La matrice des gains est conçue de sorte qu'il est préférable que les deux joueurs coopèrent toujours, mais vous pouvez gagner (généralement) en choisissant Neutre ou Défection.
Voici quelques exemples de robots (concurrents).
# turns out if you don't actually have to implement __init__(). TIL!
class AllC:
def round(self, _): return "C"
class AllN:
def round(self, _): return "N"
class AllD:
def round(self, _): return "D"
class RandomBot:
def round(self, _): return random.choice(["C", "N", "D"])
# Actually using an identically-behaving "FastGrudger".
class Grudger:
def __init__(self):
self.history = []
def round(self, last):
if(last):
self.history.append(last)
if(self.history.count("D") > 0):
return "D"
return "C"
class TitForTat:
def round(self, last):
if(last == "D"):
return "D"
return "C"
Votre bot est une classe Python3. Une nouvelle instance est créée pour chaque partie, et round()
est appelée à chaque tour, avec le choix de votre adversaire lors du dernier tour (ou Aucun, s'il s'agit du premier tour)
Il y a une prime de 50 représentants pour le gagnant en un mois environ.
Détails
- Chaque bot joue tous les autres bots (1v1), y compris lui-même, dans les rounds [SUPPRIMÉ].
- Failles standard interdites.
- Ne jouez avec rien en dehors de votre classe ou d'autres manigances sournoises.
- Vous pouvez soumettre jusqu'à cinq bots.
- Oui, vous pouvez implémenter une poignée de main.
- Toute réponse autre que
C
,N
ouD
sera considérée comme silencieuseN
. - Les points de chaque bot de chaque partie jouée seront totalisés et comparés.
Manette
Autres langues
Je jetterai ensemble une API si quelqu'un en a besoin.
Notes: 2018-11-27
27 bots, 729 games.
name | avg. score/round
----------------|-------------------
PatternFinder | 3.152
DirichletDice2 | 3.019
EvaluaterBot | 2.971
Ensemble | 2.800
DirichletDice | 2.763
Shifting | 2.737
FastGrudger | 2.632
Nash2 | 2.574
HistoricAverage | 2.552
LastOptimalBot | 2.532
Number6 | 2.531
HandshakeBot | 2.458
OldTitForTat | 2.411
WeightedAverage | 2.403
TitForTat | 2.328
AllD | 2.272
Tetragram | 2.256
Nash | 2.193
Jade | 2.186
Useless | 2.140
RandomBot | 2.018
CopyCat | 1.902
TatForTit | 1.891
NeverCOOP | 1.710
AllC | 1.565
AllN | 1.446
Kevin | 1.322
la source
while len(botlist) > 1:
avecbotlist.remove(lowest_scoring_bot)
au bas de la boucle, vous obtenez un tournoi d'élimination avec des résultats intéressants.Réponses:
EvaluaterBot
Gagne contre tous les bots précédemment soumis sauf (peut-être) le bot aléatoire (mais cela pourrait avoir un avantage, car il choisit D dans un tirage au sort et D devrait être optimal) et joue un tirage constant contre lui-même.
la source
Équilibre de Nash
Ce bot a suivi un cours de théorie des jeux à l'université mais était paresseux et n'est pas allé à la classe où ils ont couvert les jeux itérés. Il ne joue donc qu'à un seul jeu d'équilibre mixte de Nash. Il s'avère que 1/5 2/5 2/5 est le NE mixte pour les gains.
Équilibre constant de Nash
Ce robot a pris une ou deux leçons de son frère paresseux. Le problème de son frère paresseux était qu'il ne profitait pas de stratégies fixes. Cette version vérifie si l'adversaire est un joueur constant ou titfortat et joue en conséquence, sinon il joue l'équilibre régulier de Nash.
Son seul inconvénient est qu'il se situe en moyenne à 2,2 points par tour en jouant contre lui-même.
la source
class NashEquilibrium: def round(self, _): a = random.random() for k, v in [(0.2, "C"), (0.6, "N"), (1, "D")]: if a <= k: return v
TatForTit
Ce bot alternera la sélection de DNDN tandis que TitForTat alterne CDCD, pour un gain net moyen de 3 points par tour si j'ai lu correctement la matrice de paiement. Je pense que cela pourrait être optimal contre TitForTat. Évidemment, il pourrait être amélioré pour détecter un adversaire non-TFT et adopter d'autres stratégies, mais je visais juste la prime d'origine.
la source
PatternFinder
Ce bot recherche les occurrences précédentes de l'état de jeu récent pour voir comment l'adversaire a réagi à ces occurrences, avec une préférence pour les matchs de modèle plus longs et les matchs plus récents, puis joue le coup qui "battra" le coup prévu de l'adversaire. Il y a beaucoup de place pour qu'il soit plus intelligent avec toutes les données dont il assure le suivi, mais j'ai manqué de temps pour y travailler.
la source
Jade
Commence optimiste, mais devient progressivement plus amer lorsque l'adversaire refuse de coopérer. Beaucoup de constantes magiques qui pourraient probablement être modifiées, mais cela ne fera probablement pas assez bien pour justifier le temps.
la source
Ensemble
Cela exécute un ensemble de modèles connexes. Les modèles individuels prennent en compte différentes quantités d'historique et ont la possibilité de toujours choisir le mouvement qui optimisera la différence de paiement attendue, ou de sélectionner au hasard un mouvement proportionnel à la différence de paiement attendue.
Chaque membre de l'ensemble vote ensuite son choix préféré. Ils obtiennent un nombre de voix égal à ce qu'ils ont gagné de plus que l'adversaire (ce qui signifie que les modèles terribles obtiendront des votes négatifs). Quel que soit le coup gagnant, le vote est alors sélectionné.
(Ils devraient probablement répartir leurs votes entre les mouvements proportionnellement à leur préférence pour chacun, mais je m'en fiche assez de le faire maintenant.)
Il bat tout ce qui a été publié jusqu'à présent, sauf EvaluaterBot et PatternFinder. (Un contre un, il bat EvaluaterBot et perd contre PatternFinder).
Cadre de test
Au cas où quelqu'un d'autre le trouverait utile, voici un cadre de test pour examiner les correspondances individuelles. Python2. Mettez simplement tous les adversaires qui vous intéressent dans adversants.py et changez les références à Ensemble par les vôtres.
la source
OldTitForTat
Le joueur de la vieille école est trop paresseux pour mettre à jour les nouvelles règles.
la source
NeverCOOP
Si le bot adverse est défectueux ou neutre, choisissez le défaut. Sinon, si c'est le premier tour ou que le bot adverse coopère, choisissez neutre. Je ne sais pas à quel point cela fonctionnera bien ...
la source
if(last):
dans votre bot Grudger, en détectant s'il y a eu un tour précédent.None in "ND"
les erreurs.if last and last in "ND":
c'était trop compliqué?LastOptimalBot
Suppose que le bot adverse jouera toujours le même coup à nouveau et choisit celui qui a le meilleur gain contre lui.
Moyennes:
la source
return last
.return last
, LOB passerait 18-9 sur 6 rounds plutôt que les 13-10 sur 5 rounds qu'il obtient actuellement. Je pense que c'est bien comme ça - ne vous inquiétez pas d'optimiser les robots d'exemple.return last
serait un meilleur T4T pour ce défi, je penseif(last): return last; else: return "C"
c'est pire.Imitateur
Copie le dernier coup de l'adversaire.
Je ne m'attends pas à ce que cela fonctionne bien, mais personne n'avait encore implémenté ce classique.
la source
Dés de Dirichlet améliorés
Il s'agit d'une version améliorée de Dirichlet Dice. Au lieu de prendre la distribution multinomiale attendue de la distribution de Dirichlet, il tire une distribution multinomiale au hasard de la distribution de Dirichlet. Ensuite, au lieu de dessiner à partir du multinomial et de donner la réponse optimale à cela, il donne la réponse attendue optimale au multinomial donné en utilisant les points. Le caractère aléatoire a donc été essentiellement déplacé du tirage multinomial au tirage de Dirichlet. De plus, les prieurs sont plus plats maintenant, pour encourager l'exploration.
Il est "amélioré" car il rend compte du système de points en donnant la meilleure valeur attendue par rapport aux probabilités, tout en conservant son caractère aléatoire en dessinant les probabilités elles-mêmes. Avant, j'essayais simplement de faire le meilleur gain attendu à partir des probabilités attendues, mais cela a mal tourné car il est resté bloqué et n'a pas suffisamment exploré pour mettre à jour ses dés. Il était également plus prévisible et exploitable.
Soumission originale:
Dirichlet Dice
Fondamentalement, je suppose que la réponse de l'adversaire à ma dernière sortie est une variable multinomiale (dés pondérés), une pour chacune de mes sorties, donc il y a un dé pour "C", un pour "N" et un pour "D" . Donc, si mon dernier lancer était, par exemple, un "N" alors je lance les "N-dés" pour deviner quelle serait leur réponse à mon "N". Je commence par un Dirichlet avant qui suppose que mon adversaire est quelque peu "intelligent" (plus susceptible de jouer celui avec le meilleur gain contre mon dernier jet, le moins susceptible de jouer celui avec le pire gain). Je génère la distribution multinomiale "attendue" à partir du précédent Dirichlet approprié (il s'agit de la valeur attendue de la distribution de probabilité sur leurs poids de dés). Je lance les dés pondérés de ma dernière sortie,
À partir du troisième tour, je fais une mise à jour bayésienne du Dirichlet approprié avant la dernière réponse de mon adversaire à la chose que j'ai jouée il y a deux tours. J'essaie d'apprendre de manière itérative leur pondération en dés.
J'aurais pu aussi simplement choisir la réponse avec le meilleur résultat «attendu» une fois que les dés ont été générés, au lieu de simplement lancer les dés et de répondre au résultat. Cependant, je voulais garder l'aléatoire, afin que mon bot soit moins vulnérable à ceux qui tentent de prédire un modèle.
la source
Kevin
Choisit le pire choix. Le pire robot créé.
Inutile
Il regarde les deux derniers coups effectués par l'adversaire et choisit le plus de choses non faites sinon il choisit quelque chose au hasard. Il existe probablement une meilleure façon de procéder.
la source
Moyenne historique
Regarde l'histoire et trouve l'action qui aurait été la meilleure en moyenne. Démarre la coopérative.
la source
Moyenne pondérée
Le comportement de l'adversaire est modélisé comme un triangle rectangle avec des coins pour CND à 0,0 0,1 1,0 respectivement. Chaque mouvement de l'adversaire déplace le point dans ce triangle vers ce coin, et nous jouons pour battre le mouvement indiqué par le point (avec C étant donné une petite tranche ajustable du triangle). En théorie, je voulais que cela ait une mémoire plus longue avec plus de poids par rapport aux mouvements précédents, mais en pratique, la méta actuelle favorise les bots qui changent rapidement, donc cela se transforme en une approximation de LastOptimalBot contre la plupart des ennemis. Affichage pour la postérité; peut-être que quelqu'un sera inspiré.
la source
Tétragramme
Essayez de trouver un schéma dans les mouvements de l'adversaire, en supposant qu'il regarde également notre dernier mouvement.
la source
Poignée de main
Reconnaît quand il joue contre lui-même, puis coopère. Sinon, imite LastOptimalBot, ce qui semble être la meilleure stratégie sur une ligne. Fonctionne moins bien que LastOptimalBot, d'un montant inversement proportionnel au nombre de tours. Évidemment, ce serait mieux s'il y en avait plus sur le terrain * toux ** clin d'œil *.
la source
ShiftingOptimalBot
Ce bot utilise l'algorithme de LastOptimalBot tant qu'il gagne. Si l'autre bot commence à le prédire, cependant, il commencera à jouer le coup que son adversaire a joué en dernier (qui est le coup qui bat le coup qui battrait LastOptimalBot). Il parcourt les transpositions simples de ces algorithmes tant qu'il continue de perdre (ou lorsqu'il s'ennuie en dessinant beaucoup).
Honnêtement, je suis surpris que LastOptimalBot soit assis en 5ème position lorsque je poste ceci. Je suis assez certain que cela fera mieux, en supposant que j'ai écrit ce python correctement.
la source
Poignée de main
Pourquoi le motif vous correspond-il? Poignée de main et coopérez.
la source
import PatternFinder
triche dans mes livres.Hardcoded
Joue simplement une séquence codée en dur de mouvements optimisés pour battre certains des meilleurs robots déterministes.
la source