Je cherche à mettre en place un système basé sur le hasard qui est biaisé par un événement antérieur.
Contexte: Il y a quelques années, je me souviens d'une mise à jour de World of Warcraft annonçant la mise en place d'un nouveau calculateur de chances qui contrecarrerait les chaînes d'événements épineuses. (par exemple faire des coups critiques ou esquiver plusieurs fois de suite). L'idée était que, dans l'éventualité où vous éviteriez un coup, les chances d'esquiver le prochain coup seraient réduites, mais cela fonctionnerait dans les deux sens. Ne pas éviter un coup augmenterait également les chances d'esquiver le prochain coup. L'astuce majeure ici était que, sur plusieurs essais, la chance d'esquiver correspondrait toujours au pourcentage donné au joueur dans sa feuille de statistiques.
Ce type de système m'intriguait beaucoup à l'époque et je suis maintenant dans la situation d'avoir besoin d'une telle solution.
Voici mes ennuis:
- J'imagine que je serais capable de trouver des ressources en ligne sur la mise en œuvre d'un tel système, mais il me manque peut-être juste les mots à la mode pertinents pour le trouver.
- J'ai également besoin de cette approche pour s'adapter à un système qui n'est pas binomial (c'est-à-dire deux résultats), mais qui contient plutôt quatre événements mutuellement exclusifs.
Mon approche actuelle est similaire à celle d'un système de ticket de tombola. Lorsqu'un événement se produit, je modifie les poids en faveur de tous les autres événements. Cela pourrait fonctionner si les quatre événements étaient censés être tout aussi probables, mais dans mon cas, le sur doit être beaucoup plus répandu. Mais comme l'événement principal se produit plus souvent, il déplace les poids de l'autre beaucoup plus haut que prévu et je n'arrive pas à trouver les chiffres pour les déplacements de poids nécessaires pour conserver le nombre moyen de tickets autour des valeurs initiales de l'événement. donné.
Quelques indications de direction ou un exemple clair seraient très appréciés.
Réponses:
En gros, vous demandez un générateur d'événements "semi-aléatoire" qui génère des événements avec les propriétés suivantes:
Le taux moyen auquel chaque événement se produit est spécifié à l'avance.
Le même événement est moins susceptible de se produire deux fois de suite qu’il ne le serait au hasard.
Les événements ne sont pas totalement prévisibles.
Une solution consiste à implémenter d’abord un générateur d’événements non aléatoires répondant aux objectifs 1 et 2, puis à ajouter de l’aléatoire à l’objectif 3.
Pour le générateur d'événements non aléatoires, nous pouvons utiliser un algorithme de dithering simple . Plus précisément, prenons p 1 , p 2 , ..., p n les vraisemblances relatives des événements 1 à n , et s = p 1 + p 2 + ... + p n la somme des poids. Nous pouvons ensuite générer une séquence d'événements non aléatoires au maximum équidistribuée au maximum en utilisant l'algorithme suivant:
Initialement, posons e 1 = e 2 = ... = e n = 0.
Pour générer un événement, incrémentez chaque e i de p i et indiquez l’événement k pour lequel e k est le plus grand (rompre les liens à votre guise).
Décrémentez e k de s et répétez à partir de l’étape 2.
Par exemple, étant donné trois événements A, B et C, avec p A = 5, p B = 4 et p C = 1, cet algorithme génère quelque chose comme la séquence de sorties suivante:
Remarquez comment cette séquence de 30 événements contient exactement 15 As, 12 Bs et 3 Cs. Ce n'est pas tout à fait la distribution optimale - il y a quelques occurrences de deux As consécutives, ce qui aurait pu être évité - mais cela s'en rapproche.
Maintenant, pour ajouter un caractère aléatoire à cette séquence, vous avez plusieurs options (qui ne s’excluent pas nécessairement):
Vous pouvez suivre les conseils de Philipp et conserver une "suite" de N événements à venir, pour un nombre N de taille appropriée . Chaque fois que vous devez générer un événement, vous choisissez un événement aléatoire dans la console, puis vous le remplacez par l'événement suivant généré par l'algorithme de dithering ci-dessus.
En appliquant ceci à l'exemple ci-dessus, avec N = 3, on obtient par exemple:
alors que N = 10 donne le résultat le plus aléatoire:
Notez que les événements communs A et B se retrouvent avec beaucoup plus de courses en raison du brassage, alors que les rares événements C sont encore assez bien espacés.
Vous pouvez injecter un caractère aléatoire directement dans l'algorithme de dithering. Par exemple, au lieu d’incrémenter e i de p i à l’étape 2, vous pouvez l’incrémenter de p i × random (0, 2), où random ( a , b ) est un nombre aléatoire uniformément réparti entre a et b ; cela donnerait une sortie comme celle-ci:
ou vous pouvez incrémenter e i de p i + aléatoire (- c , c ), ce qui produirait (pour c = 0,1 × s ):
ou, pour c = 0,5 × s :
Notez comment le schéma additif a un effet de randomisation beaucoup plus fort pour les événements rares C que pour les événements communs A et B, par rapport au processus multiplicatif; cela pourrait ou non être souhaitable. Bien sûr, vous pouvez également utiliser une combinaison de ces schémas, ou tout autre ajustement des incréments, tant que cela préserve la propriété que l' incrément moyen de e i est égal à p i .
Vous pouvez également perturber la sortie de l'algorithme de dithering en remplaçant parfois l'événement k choisi par un événement aléatoire (choisi en fonction des poids bruts p i ). Tant que vous utilisez également le même k à l'étape 3 que celui que vous avez généré à l'étape 2, le processus de dithering aura toujours tendance à égaliser les fluctuations aléatoires.
Par exemple, voici un exemple de sortie avec 10% de chances que chaque événement soit choisi au hasard:
et voici un exemple avec 50% de chances que chaque sortie soit aléatoire:
Vous pouvez aussi envisager de nourrir un mélange d'événements purement aléatoires et tramées dans une plate - forme / piscine mélange, comme décrit ci - dessus, ou randomiser peut - être l'algorithme de tramage en choisissant k au hasard, pesée par les e i s (traitement de poids négatifs zéro).
Ps. Voici quelques séquences d'événements complètement aléatoires, avec les mêmes taux moyens, à des fins de comparaison:
Tangent: Puisqu'il y a eu un débat dans les commentaires sur la nécessité, pour les solutions basées sur le pont, de permettre au pont de se vider avant de le remplir, j'ai décidé de faire une comparaison graphique de plusieurs stratégies de remplissage du pont:
Tracé de plusieurs stratégies pour générer des lancers de pièces semi-aléatoires (avec un rapport 50:50 des têtes aux queues en moyenne). L’axe horizontal correspond au nombre de retournements, l’axe vertical correspond à la distance cumulée par rapport au rapport attendu, mesurée comme suit: (têtes - queues) / 2 = têtes - retournements / 2.
Les lignes rouges et vertes du graphique montrent deux algorithmes non basés sur le pont pour la comparaison:
Les trois autres lignes (bleu, violet et cyan) illustrent les résultats de trois stratégies basées sur les decks, chacune mise en œuvre à l'aide d'un deck de 40 cartes, qui est initialement rempli de 20 cartes "têtes" et de 20 cartes "queues":
Bien entendu, l’intrigue ci-dessus n’est qu’une simple réalisation d’un processus aléatoire, mais elle est raisonnablement représentative. En particulier, vous pouvez voir que tous les processus basés sur le deck ont un biais limité et restent assez proches de la ligne rouge (déterministe), alors que la ligne verte purement aléatoire finit par s’égarer.
(En fait, la différence entre les lignes bleue, violette et cyan par rapport à zéro est strictement délimitée par la taille du pont: la ligne bleue ne peut jamais dériver plus de 10 pas de zéro, la ligne violette ne peut en avoir que 15. et la ligne cyan peut dériver au maximum de 20 pas de zéro.Bien sûr, aucune ligne atteignant réellement sa limite est extrêmement improbable, car elle a tendance à se rapprocher de zéro si elle s’éloigne trop de.)
En un coup d'œil, il n'y a pas de différence évidente entre les différentes stratégies basées sur le pont (bien que, en moyenne, la ligne bleue reste un peu plus proche de la ligne rouge et que la ligne cyan reste un peu plus éloignée), mais un examen plus attentif de la ligne bleue révèle un motif déterministe distinct: tous les 40 tirages (marqués par les lignes verticales grises en pointillés), la ligne bleue correspond exactement à la ligne rouge à zéro. Les lignes violettes et cyan ne sont pas aussi strictement contraintes et peuvent rester à l’écart de zéro à tout moment.
Pour toutes les stratégies basées sur les decks, la caractéristique importante qui garde leur variation limitée est le fait que, bien que les cartes soient tirées du deck au hasard, le deck est rempli de manière déterministe. Si les cartes utilisées pour remplir le paquet étaient elles-mêmes choisies au hasard, toutes les stratégies basées sur le paquet deviendraient impossibles à distinguer du choix au hasard (ligne verte).
la source
Ne lancez pas de dés, distribuez des cartes.
Prenez tous les résultats possibles de votre RNG, mettez-les dans une liste, mélangez-les au hasard et renvoyez les résultats dans l'ordre aléatoire. Lorsque vous êtes à la fin de la liste, répétez.
Les résultats seront toujours distribués uniformément, mais les résultats individuels ne seront pas répétés à moins que le dernier de la liste ne soit également le premier de la suivante.
Lorsque cela est un peu trop prévisible à votre goût, vous pouvez utiliser une liste
n
indiquant le nombre de résultats possibles et multiplier par chacun les résultats possiblesn
avant de les mélanger. Ou vous pouvez remanier la liste avant qu’elle soit complètement itérée.la source
Vous pouvez essayer un graphe aléatoire de Markov . Considérez chaque événement pouvant survenir comme un nœud d’un graphique. À partir de chaque événement, créez un lien vers un autre événement qui pourrait éventuellement suivre. Chacun de ces liens est pondéré par quelque chose appelé la probabilité de transition . Ensuite, vous effectuez une marche aléatoire du graphique en fonction du modèle de transition.
Par exemple, vous pouvez avoir un graphique qui représente le résultat d'une attaque (coup critique, esquive, etc.). Initialisez le nœud de départ à celui choisi au hasard en fonction des statistiques du joueur (lancez simplement les dés). Ensuite, lors de la prochaine attaque, décidez de ce qui se passera par la suite, en fonction du modèle de transition.
Il faut prendre soin de décider comment pondérer les transitions. D'une part, toutes les transitions en sortie d'un nœud doivent être additionnées jusqu'à une probabilité de 1. Une chose simple à faire est d'effectuer une transition de chaque nœud à chaque autre nœud, avec des pondérations équivalentes à la probabilité que ces événements se produisent. a priori , étant donné que l'événement en cours ne peut plus se reproduire.
Par exemple, si vous avez trois événements:
Vous pouvez configurer le modèle de transition de sorte qu'un coup critique ne se produise plus en redistribuant uniformément sa masse de probabilité aux autres événements:
EDIT: Comme le disent les commentaires ci-dessous, ce modèle n’est pas assez compliqué pour obtenir le comportement souhaité. Au lieu de cela, vous devrez peut-être ajouter plusieurs états supplémentaires!
la source
Voici une implémentation que j'ai créée en C # et qui va:
J'ai ajouté quelques commentaires pour que vous puissiez voir ce que je fais.
J'espère que cela vous aidera, veuillez suggérer des améliorations à ce code dans les commentaires, merci!
la source
Permettez-moi de généraliser un peu la réponse de mklingen . Fondamentalement, vous voulez implémenter Fallacy du Gambler , bien que je vais fournir une méthode plus générale ici:
Supposons qu'il existe
n
des événements possibles avec des probabilitésp_1, p_2, ..., p_n
. Quand un événement sei
produit, sa probabilité doit être redimensionnée avec un facteur0≤a_i≤1/p_i
(ce dernier est important, sinon vous vous retrouvez avec une probabilité supérieure à un et les autres événements doivent avoir des probabilités négatives , ce qui signifie fondamentalement des " anti " événements. Ou quelque chose), bien que typiquementa_i<1
. Vous pouvez par exemple choisira_i=p_i
, ce qui signifie que la probabilité qu'un événement se produise une seconde fois est la probabilité initiale que l'événement se produise précisément deux fois de suite, par exemple, un second tirage au sort aurait une probabilité de 1/4 au lieu de 1/2. D'autre part, vous pouvez également en avoira_i>1
, ce qui signifierait déclencher un "coup de chance / malheur".Tous les autres événements doivent rester également probables les uns par rapport aux autres, c'est-à-dire qu'ils doivent tous être redimensionnés avec le même facteur, de
b_i
sorte que la somme de toutes les probabilités soit égale à un, c'est-à-direJusqu'ici, si simple. Mais ajoutons maintenant une autre exigence: compte tenu de toutes les séquences possibles de deux événements, les probabilités à événement unique extraites de celle-ci doivent être les probabilités d’origine.
Laisser
Indiquez la probabilité que l'événement se
j
produise après l'événementi
et notez quep_ij≠p_ji
sauf sib_i=b_j (2)
(ce qui(1)
impliquea_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j
). C’est aussi ce que le théorème de Bayes exige et cela implique aussijuste comme désiré. Notez simplement que cela signifie que l’on
a_i
corrige tous les autres.Voyons maintenant ce qui se passe lorsque nous appliquons cette procédure plusieurs fois, c'est-à-dire pour des séquences de trois événements ou plus. Il existe essentiellement deux options pour le choix des probabilités truquées du troisième événement:
a) Oubliez le premier événement et installez-vous comme si seulement le second se produisait, c'est-à-dire
Notez que cela viole généralement Bayes, car par exemple
p_jik≠p_ikj
dans la plupart des cas.b) Utilisez les probabilités
p_ij
(pour fixei
) comme nouvelles probabilités àpi_j
partir desquelles vous obtenez les nouvelles probabilitéspi_jk
pour que l'événementk
se produise ensuite. Que vous le modifiiezai_j
ou non dépend de vous, mais sachez que les nouveauxbi_j
sont définitivement différents en raison de la modificationpi_j
. Là encore, le choix deai_j
est probablement limité en exigeant que toutes les permutationsijk
se produisent avec la même probabilité. Voyons voir...et leurs permutations cycliques, qui doivent être égales pour les cas respectifs.
J'ai bien peur que ma suite sur ce sujet devra attendre un moment ...
la source
Je pense que la meilleure option consiste à utiliser une sélection d’éléments pondérée de manière aléatoire. Il existe une implémentation pour C # ici , mais ils peuvent être facilement trouvés ou créés pour d’autres langues.
L'idée serait de réduire le poids d'une option à chaque fois qu'il est sélectionné et de l'augmenter chaque fois qu'il n'est pas sélectionné.
Par exemple, si vous diminuez le poids de l'option choisie
NumOptions-1
et que vous augmentez le poids de toutes les autres options de 1 (en prenant soin de supprimer les éléments de poids <0 et de les relire lorsqu'ils dépassent 0) , chaque option sera sélectionnée approximativement. le même nombre de fois sur une longue période, mais les options récemment choisies seront beaucoup moins susceptibles d'être choisies.Le problème avec l'utilisation d'un ordre aléatoire, comme suggéré par de nombreuses autres réponses, est qu'après chaque option choisie, vous pouvez prédire avec une certitude à 100% quelle option sera sélectionnée ensuite. Ce n'est pas très aléatoire.
la source
Ma réponse est incorrecte, mon test était imparfait.
Je laisse cette réponse ici pour la discussion et les commentaires qui soulignent les failles de cette conception, mais le test réel était incorrect.
la source
Vous pouvez faire ce qui est essentiellement un filtre. Gardez une trace des n événements passés. La probabilité est le filtre parmi certains appliqué à ces événements. Le filtre 0 est la probabilité de base, si 0 alors vous avez esquivé, si 1 vous avez échoué. Supposons que la base était de 25% et que le filtre diminue de moitié à chaque itération. Votre filtre serait alors:
N'hésitez pas à continuer si vous le souhaitez. La probabilité globale de ce schéma est légèrement supérieure à la probabilité de base de 0,25. En fait, la probabilité, étant donné le même schéma, est (j'appelle x la probabilité réelle, p est l'entrée de probabilité):
La résolution de x, on trouve la réponse est
p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8)
, ou pour notre cas donné,x=0.38461538461
. Mais ce que vous voulez vraiment, c'est trouver p, étant donné x. Cela s'avère être un problème plus difficile. Si vous supposez un filtre infini, le problème devientx+x*p=2*p
, oup=x/(2-x)
. Donc, en augmentant votre filtre, vous pourriez alors résoudre un nombre p qui vous donnera en moyenne les mêmes résultats, mais à un taux dépendant des succès récents.Fondamentalement, vous utilisez les valeurs précédentes pour déterminer le seuil d'acceptation de cette ronde et prenez une valeur aléatoire. Produisez ensuite la valeur aléatoire suivante en fonction du filtre.
la source
Tout comme vous l’avez proposé, l’une des solutions consiste à mettre en œuvre un système aléatoire pondéré. L'idée est de créer un générateur de nombres aléatoires (ou de résultats) où les pondérations et les résultats peuvent être modifiés.
Voici une implémentation de ceci en Java.
EDIT Dans le cas où vous souhaitez ajuster les poids automatiquement, par exemple, augmentez les chances de A lorsque le résultat est B. Vous pouvez soit,
nextOutcome()
méthode, de sorte qu'il modifie le poids en fonction du résultatsetWeight()
pour modifier le poids de en fonction du résultat.la source