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:
A B A B C A B A B A A B A B C A B A B A A B A B C A B A B A
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:
A B A B C A B B A B A B C A A A A B B A B A C A B A B A B A
alors que N = 10 donne le résultat le plus aléatoire:
A A B A C A A B B B A A A A A A C B A B A A B A C A C B B B
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:
A B B C A B A A B A A B A B A A B A A A B C A B A B A C A B
ou vous pouvez incrémenter e i de p i + aléatoire (- c , c ), ce qui produirait (pour c = 0,1 × s ):
B A A B C A B A B A B A B A C A B A B A B A A B C A B A B A
ou, pour c = 0,5 × s :
B A B A B A C A B A B A A C B C A A B C B A B B A B A B C A
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:
B A C A B A B A C B A A B B A B A B A B C B A B A B C A B A
et voici un exemple avec 50% de chances que chaque sortie soit aléatoire:
C B A B A C A B B B A A B A A A A A B B A C C A B B A B B C
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:
A C A A C A B B A A A A B B C B A B B A B A B A A A A A A A
B C B A B C B A A B C A B A B C B A B A A A A B B B B B B B
C A A B A A B B C B B B A B A B A A B A A B A B A C A A B A
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:
- Ligne rouge, tramage déterministe : les résultats pairs sont toujours des têtes, les résultats impairs sont toujours des queues.
- Ligne verte, retournements aléatoires indépendants : chaque résultat est choisi indépendamment au hasard, avec une probabilité de tête de 50% et une chance de queue de 50%.
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":
- Ligne bleue, remplir à vide : les cartes sont tirées au hasard jusqu'à ce que le paquet soit vide, puis le paquet est rempli de 20 cartes "têtes" et de 20 cartes "queues".
- Ligne violette, à remplir à moitié vide : les cartes sont tirées au sort jusqu'à ce qu'il reste 20 cartes dans le paquet; le paquet est ensuite complété avec 10 cartes "têtes" et 10 cartes "queues".
- Ligne cyan, à remplir en permanence : les cartes sont tirées au hasard; les tirages pairs sont immédiatement remplacés par une carte "têtes", et les tirages impairs avec une carte "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).