151 votes

Besoin d'un générateur aléatoire prévisible

Je suis un web-développeur de jeu et j'ai eu un problème avec des nombres aléatoires. Disons qu'un joueur a 20% de chance d'obtenir un coup critique avec son épée. Cela signifie que, 1 de 5 hits devraient être critiques. Le problème est que j'ai obtenu de très mauvais résultats dans la vraie vie, parfois les joueurs reçoivent 3 crits en 5 coups, et parfois aucun dans les 15 hits. Les batailles sont plutôt courtes (de 3 à 10 coups) il est donc important d'obtenir une bonne répartition aléatoire.

Actuellement j'utilise le PHP la fonction mt_rand(), mais nous sommes simplement en déplaçant notre code C++, donc je veux résoudre ce problème dans notre jeu, le moteur de nouveau.

Je ne sais pas si la solution est certains uniforme générateur de hasard, ou peut-être de se rappeler précédente aléatoire unis pour forcer une bonne distribution.

226voto

Esko Luontola Points 53877

Cela signifie que, 1 de 5 hits devraient être critiques. Le problème est que j'ai obtenu de très mauvais résultats dans la vraie vie - parfois, les joueurs reçoivent 3 crits en 5 coups, et parfois aucun dans les 15 hits.

Ce que vous avez besoin est un shuffle sac. Il résout le problème du vrai aléatoire étant trop aléatoire pour les jeux.

L'algorithme est un peu comme ceci: Vous mettez 1 critique et 4 non-coups critiques dans un sac. Ensuite, vous leur ordre aléatoire dans le sac et en chercher un à un. Lorsque le sac est vide, vous le remplissez à nouveau avec les mêmes valeurs et aléatoire. De cette façon, vous obtiendrez en moyenne 1 coup critique par 5 hits, et au plus 2 critiques et 8 non-coups critiques dans une rangée. Augmenter le nombre d'éléments dans le sac pour plus de hasard.

Voici un exemple d' une mise en œuvre (en Java) et ses tests que j'ai écrit il y a quelques temps.

114voto

ceejayoz Points 85962

Vous avez une incompréhension de ce hasard moyens.

Laquelle de ces est plus aléatoire?

alt textalt text

Tandis que le second tracé ressemble plus uniformément répartie, le plus aléatoire est en fait la première parcelle. L'esprit humain voit souvent des modèles dans l'aléatoire, de sorte que nous voyons les mottes dans la première parcelle comme des modèles, mais ils ne sont pas - ils sont seulement une partie d'un échantillon choisi au hasard.

90voto

AHelps Points 1171

Étant donné le comportement que vous demandez, je pense que vous êtes rendant aléatoire la mauvaise variable.

Plutôt que de randomisation si ce hit sera critique, essayez de randomisation nombre de tours jusqu'à ce que le prochain coup critique se produit. Par exemple, il suffit de choisir un nombre entre 2 et 9 à chaque fois que le joueur obtient un critique, et ensuite leur donner une critique suivante après que de nombreuses séries ont passé. Vous pouvez également utiliser des dés de méthodes pour se rapprocher d'une distribution normale, par exemple, vous obtiendrez votre prochaine critique dans 2D4 tours.

Je crois que cette technique est utilisé dans les jeux de rôle qui ont au hasard des rencontres dans le monde d'en haut: vous randomize un compteur de pas, et après de nombreuses étapes, vous obtenez frapper à nouveau. Il se sent beaucoup plus juste parce que vous avez failli ne jamais se faire frapper par deux rencontres en ligne -- si cela arrive encore une fois, les joueurs se irritable.

53voto

Adam Wright Points 31715

Tout d'abord, définir le "bon" de la distribution. Les nombres aléatoires sont, bien, aléatoire les résultats que vous voyez sont totalement compatibles avec les (pseudo) aléatoire.

Étendre sur ce, je suppose que ce que vous voulez, c'est un certain sentiment de "l'équité", de sorte que l'utilisateur ne peut pas aller de 100 tours sans succès. Si oui, j'aimerais garder une trace du nombre de défaillances depuis le dernier succès, et le poids le résultat généré. Supposons que vous voulez de 1 à 5 rouleaux pour "réussir". Afin de vous générer aléatoirement un nombre de 1 à 5, et si c'est 5, grande.

Si non, le record de l'échec, et la prochaine fois, générer un nombre de 1 à 5, mais ajouter à dire, le sol(numFailures / 2). Alors, cette fois, encore une fois, ils ont de 1 à 5 de chance. Si elles ne parviennent pas, la prochaine fois, la gagnante de l'intervalle est de 4 et 5; 2 à 5 chances de succès. Avec ces choix, après 8 échecs, ils sont certains de réussir.

39voto

Ian Terrell Points 6551

Je suis d'accord avec les réponses que réel aléatoire dans des petites séries de certains jeux n'est pas souhaitable, car il n'a semble trop injuste pour certains cas d'utilisation.

J'ai écrit un simple Shuffle Sac de la mise en œuvre dans le Rubis et fait quelques tests. La mise en œuvre fait:

  • Si elle semble toujours juste ou nous n'avons pas atteint un seuil minimal de rouleaux, il renvoie une juste frapper basé sur la probabilité normale.
  • Si la probabilité observée à partir des dernières rouleaux de fait, il semble injuste, elle renvoie un "juste-la ratification de" frapper.

Elle est réputée déloyale fondée sur les limites des probabilités. Par exemple, pour une probabilité de 20%, vous pouvez définir de 10% de la limite inférieure et de 40% de la limite supérieure.

L'utilisation de ces limites, j'ai trouvé qu'avec des séries de 10 coups, de 14,2% du temps, le vrai pseudo de la mise en œuvre produit des résultats qui ont été hors de ces limites. Environ 11% du temps, 0 les coups critiques ont été marqués en 10 essais. 3.3% du temps, 5 ou plus de coups critiques ont été débarqués sur 10. Naturellement, à l'aide de cet algorithme (avec un minimum de rouleau nombre de 5), un montant beaucoup plus faible (0.03%), de la "Fairish" s'est en dehors des limites. Même si l'application est inadéquat (plus intelligente de faire les choses, certes), il est intéressant de noter que le fait souvent, vos utilisateurs auront l'impression que c'est injuste, avec un vrai pseudo solution.

Ici est la viande de mon FairishBag écrit en Ruby. L'ensemble de la mise en œuvre rapide et la simulation de Monte Carlo est disponible ici (gist).

def fire!
  hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
    false
  elsif @rolls >= @min_rolls && observed_probability < @unfair_low
    true
  else
    rand <= @probability
  end
  @hits += 1 if hit
  @rolls += 1
  return hit
end

def observed_probability
  @hits.to_f / @rolls
end

Mise à jour: cette méthode n'est augmenter la probabilité d'obtenir un coup critique, à environ 22% en utilisant les limites ci-dessus. Vous pouvez compenser cela par la mise en son "véritable" probabilité un peu plus bas. Une probabilité de 17,5% avec le fairish modification des rendements observée à long terme de probabilité d'environ 20%, et de garder le court terme s'exécute sentiment juste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X