Notwendigkeit eines vorhersehbaren Zufallsgenerators


151

Ich bin ein Entwickler von Web-Spielen und habe ein Problem mit Zufallszahlen. Angenommen, ein Spieler hat eine 20% ige Chance, mit seinem Schwert einen kritischen Treffer zu erzielen. Das heißt, 1 von 5 Treffern sollte kritisch sein. Das Problem ist, dass ich im wirklichen Leben sehr schlechte Ergebnisse erzielt habe - manchmal erhalten Spieler 3 kritische Treffer in 5 Treffern, manchmal keine in 15 Treffern. Die Schlachten sind ziemlich kurz (3-10 Treffer), daher ist es wichtig, eine gute zufällige Verteilung zu erreichen.

Derzeit verwende ich PHP mt_rand(), aber wir verschieben unseren Code nur nach C ++, daher möchte ich dieses Problem in der neuen Engine unseres Spiels lösen.

Ich weiß nicht, ob die Lösung ein einheitlicher Zufallsgenerator ist oder ob ich mich an frühere Zufallszustände erinnern soll, um eine ordnungsgemäße Verteilung zu erzwingen.


58
Es besteht eine Wahrscheinlichkeit von 0,5% für genau 3 kritische und 2 unkritische Treffer und eine Wahrscheinlichkeit von 3,5% für 15 unkritische Treffer hintereinander, vorausgesetzt, es handelt sich um echte Zufallszahlen.
Nixuz

10
+1 bis oben. Ein Merkmal von Zufallszahlen ist, dass Sie Ausreißer erhalten.
ConcernedOfTunbridgeWells

44
@Nixus: Nein, es besteht eine Wahrscheinlichkeit von ca. 5% für 3 kritische und 2 unkritische Treffer. Sie vergessen, sich mit (5! / (3! * 2!)) = 10 zu multiplizieren. Bei einem Konfidenzniveau von 95% ist dies der Fall Es ist statistisch nicht unwahrscheinlich, dass 3 kritische Treffer in 5 Schlägen auftreten.
Erikkallen

7
Zuerst dachte ich, das sei eine dumme Frage ... wieder einmal bin ich von SO gedemütigt.
SergioL

Antworten:


39

Ich stimme den früheren Antworten zu, dass echte Zufälligkeit in kleinen Auflagen einiger Spiele unerwünscht ist - es scheint für einige Anwendungsfälle zu unfair.

Ich habe eine einfache Shuffle Bag-ähnliche Implementierung in Ruby geschrieben und einige Tests durchgeführt. Die Implementierung hat dies getan:

  • Wenn es immer noch fair erscheint oder wir einen Schwellenwert für Mindestwürfe nicht erreicht haben, wird ein fairer Treffer basierend auf der normalen Wahrscheinlichkeit zurückgegeben.
  • Wenn die beobachtete Wahrscheinlichkeit aus früheren Würfen es unfair erscheinen lässt, gibt es einen "fairen" Treffer zurück.

Es wird aufgrund von Grenzwahrscheinlichkeiten als unfair angesehen. Bei einer Wahrscheinlichkeit von 20% können Sie beispielsweise 10% als Untergrenze und 40% als Obergrenze festlegen.

Unter Verwendung dieser Grenzen stellte ich fest, dass bei Läufen von 10 Treffern in 14,2% der Fälle die echte Pseudozufallsimplementierung Ergebnisse erbrachte, die außerhalb dieser Grenzen lagen . In etwa 11% der Fälle wurden in 10 Versuchen 0 kritische Treffer erzielt. In 3,3% der Fälle wurden 5 oder mehr kritische Treffer von 10 gelandet. Mit diesem Algorithmus (mit einer Mindestwurfzahl von 5) war natürlich eine viel geringere Menge (0,03%) der "fairen" Läufe außerhalb der Grenzen . Selbst wenn die folgende Implementierung ungeeignet ist (sicherlich können klügere Dinge getan werden), ist es erwähnenswert, dass Ihre Benutzer merklich oft das Gefühl haben, dass es mit einer echten Pseudozufallslösung unfair ist.

Hier ist das Fleisch von mir FairishBagin Ruby geschrieben. Die gesamte Implementierung und schnelle Monte-Carlo-Simulation finden Sie hier (Kern) .

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

Update: Die Verwendung dieser Methode erhöht die Gesamtwahrscheinlichkeit eines kritischen Treffers auf etwa 22% unter Verwendung der oben genannten Grenzen. Sie können dies ausgleichen, indem Sie die "reale" Wahrscheinlichkeit etwas niedriger einstellen. Eine Wahrscheinlichkeit von 17,5% mit der fairen Modifikation ergibt eine beobachtete langfristige Wahrscheinlichkeit von etwa 20% und sorgt dafür, dass sich die kurzfristigen Läufe fair anfühlen.


Ich denke, dies ist die beste Lösung, die meinen Anforderungen entspricht. Die in der besten Antwort erwähnte Shuffle-Tasche ist nicht schlecht, erfordert aber viel Berechnung, und ich mag die einfachste Lösung, die zum Ziel führt.
Denker

Steve Rabin schrieb einen interessanten Artikel über Zufälligkeit in Spielen. Kurz gesagt, echtes "zufälliges" Verhalten fühlt sich für die meisten Menschen nicht wirklich zufällig an, und Studien haben dies bestätigt. Sein Artikel heißt Filtered Randomness for AI Decisions and Game Logic und erscheint in "AI Game Programming Wisdom 2" (2003). Sie sollten es überprüfen, wird wahrscheinlich für Sie nützlich sein.
Jeff Tucker

@IanTerrell Es wäre gut anzugeben, wie groß die Stichprobengröße Ihrer Tests ist, dh wie viele Kämpfe, um diese Wahrscheinlichkeiten zu bestimmen.

@ user677656: Es ist im Kern, aber es ist 100k
Ian Terrell

223

Das heißt, 1 von 5 Treffern sollte kritisch sein. Das Problem ist, dass ich im wirklichen Leben sehr schlechte Ergebnisse erzielt habe - manchmal erhalten Spieler 3 kritische Treffer in 5 Treffern, manchmal keine in 15 Treffern.

Was Sie brauchen, ist eine Shuffle-Tasche . Es löst das Problem, dass echte Zufälle für Spiele zu zufällig sind.

Der Algorithmus sieht ungefähr so ​​aus: Sie legen 1 kritischen und 4 unkritischen Treffer in eine Tasche. Dann ordnen Sie ihre Reihenfolge in der Tasche nach dem Zufallsprinzip und wählen sie einzeln aus. Wenn der Beutel leer ist, füllen Sie ihn erneut mit denselben Werten und sortieren ihn nach dem Zufallsprinzip. Auf diese Weise erhalten Sie durchschnittlich 1 kritischen Treffer pro 5 Treffer und höchstens 2 kritische und 8 unkritische Treffer hintereinander. Erhöhen Sie die Anzahl der Artikel in der Tasche, um mehr Zufälligkeit zu erzielen.

Hier ist ein Beispiel für eine Implementierung (in Java) und ihre Testfälle , die ich vor einiger Zeit geschrieben habe.


21
+ 1 für gute Idee ohne Kritik. Skalieren Sie den Beutel für ein höheres Maß an Zufälligkeit und um die Abweichungen in der kritischen Chance zwischen Spielern zu bewältigen (falls variabel von c)
TheMissingLINQ

16
Sie könnten eine Taschengröße von 10 haben. Setzen Sie 1 Treffer plus eine 30% ige Chance auf eine Sekunde ein. Wenn sich die kritische Chance ändert, können Sie die Tasche einfach wegwerfen und eine neue starten. Beachten Sie, dass bei einem solchen Schema das Risiko besteht, dass Sie (oder Ihr Gegner), wenn Sie Ihre kritische Trefferwahrscheinlichkeit und die Größe des Beutels kennen, manchmal mit Sicherheit wissen, dass Sie für eine bestimmte Anzahl von Würfen keinen weiteren kritischen Treffer erhalten. Dies könnte die Taktik beeinflussen.
Steve Jessop

3
Ja ... in so etwas laufen Ricks ähnlich wie beim Kartenzählen. Riskiere ich einen Peon oder gehe ich auf den großen Kill ein ... ein kleiner fester Satz potenzieller Ergebnisse kann das Verlustrisiko verringern und die Wahrscheinlichkeit erhöhen, "gespielt" zu werden
Matthew Whited

8
Ich mag die Shuffle-Bag-Idee, aber ich denke nicht, dass dies dem "Geist" des Spiels entspricht, da Ihre kritische Trefferwahrscheinlichkeit von 20% (was bedeutet, dass Sie in 10 Treffern keine Treffer erzielen können) keine Wahrscheinlichkeit mehr ist. Es wird genau 1 Treffer alle 5 Treffer. Darüber hinaus führt das erneute Rollen des Beutels bei einer Änderung der kritischen Trefferwahrscheinlichkeit zu einem Fehler im Spiel. Wenn mein kritischer Treffer erzielt wurde, werde ich mich selbst verzaubern, um den nächsten Kritiker früher zu bekommen: p
Michaël Carpentier

2
@ Jonathan: Wenn du die Tasche so groß machst, wie du sie gibst, wird die gesamte Idee der Tasche rückgängig gemacht: um sicherzustellen, dass innerhalb einer akzeptablen Anzahl von Würfen etwas passiert (das Kritische, das erreicht wird). Wenn Sie die Tasche 50000 groß machen, entspricht dies in etwa der Verwendung des Zufallszahlengenerators.
dstibbe

113

Sie haben ein Missverständnis darüber, was Zufall bedeutet.

Welche davon ist zufälliger?

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Während die zweite Handlung gleichmäßiger aussieht, ist die erste Handlung tatsächlich zufälliger . Der menschliche Verstand sieht Muster oft zufällig, daher sehen wir die Klumpen in der ersten Darstellung als Muster, aber sie sind es nicht - sie sind nur Teil einer zufällig ausgewählten Stichprobe.


25
Gute Numb3rs Erklärung!
RMAAlmeida

9
Technisch gesehen kann man die Zufälligkeit nicht messen. Beide Distributionen sehen für mich ziemlich willkürlich aus, obwohl ich vermute, dass beide algorithmisch generiert wurden. Sie können eine Reihe von Tests für das erste Diagramm durchführen und feststellen, dass es wahrscheinlich aus einem Prozess stammt, bei dem Punkte gemäß einer gleichmäßigen Verteilung platziert werden. Sie können jedoch nicht den Schluss ziehen, dass es zufälliger ist. Als Gegenbeispiel könnten Sie mit einem linearen Kongruenzgenerator ein Diagramm wie das erste erstellen und dann mit verstärktem Rauschen einer Zenerdiode ein Diagramm wie das zweite erstellen. Versuchen Sie das Wort unkorreliert statt zufällig.
Dietrich Epp

8
Sie können die Wahrscheinlichkeit messen, dass diese Verteilung zufällig ist.
Ceejayoz


2
Um fair zu sein, obwohl OP möglicherweise nicht die richtigen Begriffe verwendet, versteht er, dass der Zufallszahlengenerator ihm etwas mehr wie das erste Diagramm gibt, wenn er etwas mehr wie das zweite Diagramm möchte, weil es sich für den Benutzer "fairer" anfühlt .
Kip

88

Angesichts des Verhaltens, nach dem Sie fragen, denke ich, dass Sie die falsche Variable zufällig auswählen.

Anstatt zu randomisieren, ob dieser Treffer kritisch ist, versuchen Sie, die Anzahl der Runden zufällig zu bestimmen, bis der nächste kritische Treffer eintritt. Wählen Sie zum Beispiel jedes Mal, wenn der Spieler einen kritischen Punkt erhält, eine Zahl zwischen 2 und 9 und geben Sie ihm dann den nächsten kritischen Punkt, nachdem viele Runden vergangen sind. Sie können auch Würfelmethoden verwenden, um einer Normalverteilung näher zu kommen. Beispielsweise erhalten Sie in 2D4-Runden Ihren nächsten kritischen Punkt.

Ich glaube, diese Technik wird auch in RPGs verwendet, die zufällige Begegnungen in der Überwelt haben - Sie randomisieren einen Schrittzähler und nach so vielen Schritten werden Sie erneut getroffen. Es fühlt sich viel fairer an, weil man fast nie von zwei Begegnungen hintereinander getroffen wird - wenn das auch nur einmal passiert, werden die Spieler gereizt.


Ich denke, das ist eine großartige Lösung, aber wie steht es mit einer Chance von 80%?
Denker

Manchmal verwende ich auch gerne mehrdimensionale Zufallsgeneratoren. Chance zu treffen + Chance zu Macht + Chance zu kritisch. Genau wie beim Würfeln in D & D
Matthew Whited

Ich mag diese Idee, und Sie haben völlig Recht mit der Sache mit dem Schrittzähler, die zum Beispiel schon sehr lange in der endgültigen Fantasie verwendet wird
Ed James,

Ein Problem dabei ist, dass es nur funktioniert, wenn die Wahrscheinlichkeit eines kritischen Punktes zwischen den Treffern ungefähr konstant ist. Angenommen, der Spieler wirkt mitten im Kampf einen Zauber, der die Wahrscheinlichkeit eines kritischen Treffers verdoppelt. Wie passt man dann die Anzahl der Windungen an?
Alex319

+1 Sehr schön, behandelt auch weniger runde Trefferwahrscheinlichkeiten als 20% sehr leicht.
Alice Purcell

53

Definieren Sie zunächst die "richtige" Verteilung. Zufallszahlen sind zufällig - die Ergebnisse, die Sie sehen, stimmen vollständig mit der (Pseudo-) Zufälligkeit überein.

Ich gehe davon aus, dass Sie ein Gefühl von "Fairness" wünschen, sodass der Benutzer nicht 100 Runden ohne Erfolg fahren kann. In diesem Fall würde ich die Anzahl der Fehler seit dem letzten Erfolg verfolgen und das generierte Ergebnis gewichten. Nehmen wir an, Sie möchten, dass 1 von 5 Rollen "erfolgreich" ist. Sie generieren also zufällig eine Zahl von 1 bis 5, und wenn es 5 ist, ist das großartig.

Wenn nicht, notieren Sie den Fehler und generieren Sie beim nächsten Mal eine Zahl von 1 bis 5, fügen Sie jedoch beispielsweise Etage (numFailures / 2) hinzu. Diesmal haben sie also wieder eine 1: 5-Chance. Wenn sie fehlschlagen, beträgt das Gewinnintervall beim nächsten Mal 4 und 5; eine 2 in 5 Erfolgschance. Mit diesen Entscheidungen werden sie nach 8 Fehlern mit Sicherheit erfolgreich sein.


In diesem Sinne ... würde der Bereich der Zufallszahlen die Verteilung beeinflussen ... z. B. Auswahl eines Zufalls r = new Random (); r.Next (1,5) vs. r.Next (1, 1000000)% 200000
Eoin Campbell

23
+1 für das Erkennen des Problems hinter der Anfrage, anstatt dem OP mitzuteilen, dass er zufällig falsch versteht.
Boris Callens

4
Beachten Sie, dass wenn Sie dies tun, ihr Gesamtanteil an Erfolgen größer als 1 zu 5 ist. Eine Möglichkeit, dies zu umgehen, besteht darin, (zum Beispiel) 20 verschiedene zufällige Zahlen aus dem Bereich 1..100 auszuwählen und diese vorher festzulegen seien ihre Kritiker. Es ist jedoch ein Haufen mehr Buchhaltung.
Steve Jessop

"wird größer als 1 in 5 sein" - wird auf lange Sicht erwartet, meine ich.
Steve Jessop

Sie können die Startwahrscheinlichkeit etwas verkleinern, so dass der Gesamtanteil auf 1/5 reduziert wird. Ich habe nicht herausgefunden, um wie viel Sie es reduzieren müssen, aber alles ist kontinuierlich, also muss es eine richtige Antwort geben.
Steve Jessop

35

Wie wäre es, mt_rand () durch so etwas zu ersetzen?

XKCD-Comic (RFC 1149.5 gibt 4 als standardmäßige IEEE-geprüfte Zufallszahl an.)

(RFC 1149.5 gibt 4 als standardmäßige IEEE-geprüfte Zufallszahl an.)

Von XKCD .


Gut, aber wird dies das Problem der Zufallszahlenverteilung der OP lösen? ;-)
Arjan Einbu

Nicht wirklich; Er bittet um ein nicht zufälliges RNG, für das er diese Funktion verwenden könnte; Aber was er wirklich will, wird besser durch die aktuelle Top-Antwort ( stackoverflow.com/questions/910215/910224#910224 ) erklärt
Colin Pickard

28
Dies ist zufälliger als das OP will
Çağdaş Tekin

-1, weil RFC1149 keinen Abschnitt 5 hat (und alternativ gibt es keinen 1149.5); +1 für faire Zufälligkeit.
Greyfade

34

Hoffentlich hilft Ihnen dieser Artikel: http://web.archive.org/web/20090103063439/http://www.gamedev.net:80/reference/design/features/randomness/

Diese Methode zum Generieren von 'Zufallszahlen' ist in RPG / MMORPG-Spielen üblich.

Das Problem, das es löst, ist folgendes (Auszug):

Eine Klingenspinne ist an deiner Kehle. Es trifft und Sie vermissen. Es trifft wieder und Sie vermissen wieder. Und immer wieder, bis nichts mehr von dir zu schlagen ist. Du bist tot und es gibt ein zwei Tonnen schweres Spinnentier, das sich über deine Leiche freut. Unmöglich? Unwahrscheinlich? Ja. Bei genügend Spielern und genügend Zeit wird das Unwahrscheinliche jedoch fast sicher. Es war nicht so, dass die Klingenspinne hart war, es war nur Pech. Wie frustrierend. Es ist genug, um einen Spieler dazu zu bringen, aufzuhören.


1
Ich habe eine Variante dazu gehört - "ein Eins-zu-eine-Million-Ereignis passiert 6.000 Mal in der Weltbevölkerung".
Ceejayoz

19

Was Sie wollen, sind keine Zufallszahlen, sondern Zahlen, die einem Menschen zufällig erscheinen. Andere haben bereits individuelle Algorithmen vorgeschlagen, die Ihnen helfen können, wie Shuffle Bad.

Eine ausführliche und umfassende Analyse dieser Domäne finden Sie unter AI Game Programming Wisdom 2 . Das ganze Buch ist für jeden Spieleentwickler lesenswert. Die Idee der "scheinbar zufälligen Zahlen" wird in Kapitel 1 behandelt:

Gefilterte Zufälligkeit für KI-Entscheidungen und Spielelogik :

Zusammenfassung: Konventionelle Erkenntnisse legen nahe, dass Ihr Spiel umso unvorhersehbarer ist, je besser der Zufallszahlengenerator ist. Laut Psychologiestudien erscheint echte Zufälligkeit auf kurze Sicht für den Menschen jedoch oftmals entschieden zufällig. Dieser Artikel zeigt, wie zufällige KI-Entscheidungen und die Spielelogik für die Spieler zufälliger aussehen, während die statistische Zufälligkeit erhalten bleibt.

Vielleicht finden Sie auch ein anderes Kapitel interessant:

Die Statistik der Zufallszahlen

Zusammenfassung: Zufallszahlen werden am häufigsten von künstlicher Intelligenz und Spielen im Allgemeinen verwendet. Ihr Potenzial zu ignorieren bedeutet, das Spiel vorhersehbar und langweilig zu machen. Eine falsche Verwendung kann genauso schlecht sein wie das völlige Ignorieren. Wenn Sie verstehen, wie Zufallszahlen generiert werden, welche Einschränkungen und Fähigkeiten sie haben, können Sie viele Schwierigkeiten bei der Verwendung in Ihrem Spiel beseitigen. Dieser Artikel bietet Einblicke in Zufallszahlen, ihre Erzeugung und Methoden, um gute von schlechten zu trennen.


8

Sicherlich hat jede Zufallszahlengenerierung die Chance, solche Läufe zu produzieren? Sie erhalten kein ausreichend großes Probenset in 3-10 Rollen, um die entsprechenden Prozentsätze zu sehen.

Vielleicht möchten Sie eine Gnadenschwelle ... erinnern Sie sich an die letzten 10 Würfe, und wenn sie keinen kritischen Treffer erzielt haben, geben Sie ihnen ein Werbegeschenk. Glätten Sie die Schlingen und Pfeile der Zufälligkeit.


8

Ihre beste Lösung könnte darin bestehen, Spiele mit mehreren verschiedenen nicht zufälligen Schemata zu testen und das auszuwählen, das die Spieler am glücklichsten macht.

Sie können auch eine Back-Off-Richtlinie für dieselbe Nummer in einer bestimmten Begegnung versuchen, z. B. wenn ein Spieler 1in seinem ersten Zug einen würfelt und diese akzeptiert. Um einen anderen zu bekommen 1, müssen sie 2 1s hintereinander würfeln . Um ein Drittel zu bekommen 1, brauchen sie 3 in einer Reihe, ad infinitum.


7

Leider ist das, was Sie verlangen, effektiv ein nicht zufälliger Zahlengenerator - weil Sie möchten, dass frühere Ergebnisse bei der Bestimmung der nächsten Zahl berücksichtigt werden. Ich fürchte, so funktionieren Zufallszahlengeneratoren nicht.

Wenn Sie möchten, dass 1 von 5 Treffern kritisch ist, wählen Sie einfach eine Zahl zwischen 1 und 5 und sagen Sie, dass dieser Treffer kritisch ist.


1
Er möchte spielfreundliche Zufallszahlen. Wenn Sie in einigen Fällen streng zufällig generierte Zahlen verwenden, erhalten Sie "koreanische Zufallszahlen". Das sind zufällige Ergebnisse, die Spieler viel zu oft wütend und frustriert machen (fragen Sie einen Spieler der Linie 2);)
Juan Techera

Wenn der erste Treffer ein kritischer Treffer ist, sind die nächsten vier nicht. Es klingt so, wie es das OP will, aber wenn Sie es so ausdrücken, klingt es verzögert. Dafür bekommst du meine UV.
belgariontheking

-1 Sie scheinen "zufällig" mit "memoryless" zu verwechseln - en.wikipedia.org/wiki/Memorylessness
Alice Purcell

7

mt_rand () basiert auf einer Mersenne Twister- Implementierung, was bedeutet, dass es eine der besten Zufallsverteilungen liefert, die Sie erhalten können.

Anscheinend ist das, was Sie wollen, überhaupt keine Zufälligkeit. Sie sollten also zunächst genau angeben, was Sie wollen. Sie werden wahrscheinlich feststellen, dass Sie widersprüchliche Erwartungen haben - dass die Ergebnisse wirklich zufällig und nicht vorhersehbar sein sollten, gleichzeitig aber keine lokalen Abweichungen von der angegebenen Wahrscheinlichkeit aufweisen sollten -, aber dann werden sie vorhersehbar. Wenn Sie maximal 10 Nicht-Crits in einer Reihe festlegen, haben Sie den Spielern gerade gesagt, "wenn Sie 9 Nicht-Crits in einer Reihe hatten, wird der nächste mit 100% iger Sicherheit kritisch sein" - Sie könnten als Nun, ich kümmere mich überhaupt nicht um Zufälligkeit.


6

Bei so wenigen Tests sollten Sie solche Ergebnisse erwarten:

Wahre Zufälligkeit ist nur über eine große eingestellte Größe vorhersehbar, so dass es durchaus möglich ist, beim ersten Mal dreimal hintereinander eine Münze zu werfen und Köpfe zu bekommen. Bei einigen Millionen Flips werden Sie jedoch ungefähr 50-50 erhalten.


7
Obwohl es immer noch eine Chance gibt, dass Sie nach ein paar Millionen Flips immer noch nur eine Seite der Medaille gesehen haben. Wenn dies jemals passiert, sitzen Sie wahrscheinlich zu nahe an einem unendlichen Unwahrscheinlichkeitsdrang: P
Grant Peters

haha, ja, aber die Chance ist so unglaublich gering, dass die Gesetze der Mathematik besagen, dass Sie eine gleichmäßige (ish) Verteilung sehen sollten.
Ed James

6

Ich sehe viele Antworten, die vorschlagen, die zuvor generierten Zahlen zu verfolgen oder alle möglichen Werte zu mischen.

Persönlich stimme ich nicht zu, dass 3 kritische Treffer hintereinander schlecht sind. Ich stimme auch nicht zu, dass 15 Nicht-Kritiker hintereinander schlecht sind.

Ich würde das Problem lösen, indem ich die kritische Chance nach jeder Zahl selbst ändere. Beispiel (um die Idee zu demonstrieren):

int base_chance = 20;
int current_chance = base_chance;

int hit = generate_random_number(0, 100) + 1; // anything from 1 to 100
if(hit < current_chance)//Or whatever method you use to check
{
    //crit!
    if(current_chance > base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 0.8; // decrease the crit chance for the NEXT hit.
}
else
{
    //no crit.
    if(current_chance < base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 1.1; // increase the crit chance for the NEXT hit.
    //raise the current_chance
}

Je länger Sie keinen Kritiker bekommen, desto höher ist die Chance, dass Ihre nächste Aktion kritisch wird. Der von mir eingeschlossene Reset ist völlig optional und muss getestet werden, um festzustellen, ob er benötigt wird oder nicht. Es kann wünschenswert oder nicht wünschenswert sein, nach einer langen nicht kritischen Aktionskette eine höhere Wahrscheinlichkeit für einen kritischen Treffer für mehr als eine Aktion hintereinander anzugeben.

Ich werfe nur meine 2 Cent ein ...


Ich mag diese Art von Ansatz. Ich würde es wahrscheinlich anders machen. Beginnen Sie mit einer geringeren Chance und bauen Sie bis zu einem Maximum von 20% + einem zusätzlichen Prozentsatz auf, bis es trifft, und setzen Sie es erneut auf einen niedrigen Wert zurück.
Matthew

5

Die Top paar Antworten sind große Erklärungen, so dass ich nur auf einem Algorithmus konzentrieren werden , dass Sie die Wahrscheinlichkeit von „schlechten Streifen“ Kontrolle über gibt , während nie deterministisch zu werden. Ich denke, Sie sollten Folgendes tun:

Anstatt p , den Parameter einer Bernoulli-Verteilung, der Ihre Wahrscheinlichkeit eines kritischen Treffers darstellt, anzugeben, geben Sie a und b , die Parameter der Beta-Verteilung und den "konjugierten Prior" der Bernoulli-Verteilung an. Sie müssen A und B , die Anzahl der kritischen und unkritischen Treffer, im Auge behalten .

Um nun a und b anzugeben , stellen Sie sicher, dass a / (a ​​+ b) = p ist, die Chance eines kritischen Treffers. Das Schöne ist, dass (a + b) quantifiziert, wie nahe das A / (A + B) im Allgemeinen an p liegen soll.

Sie machen Ihre Probenahme wie folgt:

sei p(x)die Wahrscheinlichkeitsdichtefunktion der Beta-Verteilung. Es ist an vielen Stellen verfügbar, aber Sie können es in der GSL als gsl_ran_beta_pdf finden.

S = A+B+1
p_1 = p((A+1)/S)
p_2 = p(A/S)

Wählen Sie einen kritischen Treffer durch Stichproben aus einer Bernoulli-Verteilung mit der Wahrscheinlichkeit p_1 / (p_1 + p_2).

Wenn Sie feststellen, dass die Zufallszahlen zu viele "schlechte Streifen" aufweisen, skalieren Sie a und b , aber im Grenzfall, wenn a und b gegen unendlich gehen, haben Sie den zuvor beschriebenen Shuffle-Bag-Ansatz.

Wenn Sie dies implementieren, lassen Sie mich bitte wissen, wie es geht!


5

Wenn Sie eine Verteilung wünschen, die Wiederholungswerte abschreckt, können Sie einen einfachen Algorithmus zur Zurückweisung von Wiederholungen verwenden.

z.B

int GetRand(int nSize)
{
    return 1 + (::rand() % nSize);
}
int GetDice()
{
    static int nPrevious=-1;
    while (1) {
        int nValue = GetRand(6);
        // only allow repeat 5% of the time
        if (nValue==nPrevious && GetRand(100)<95)
            continue;
        nPrevious = nValue;
        return nValue;
    }
}

Dieser Code lehnt Wiederholungswerte in 95% der Fälle ab, sodass Wiederholungen unwahrscheinlich, aber nicht unmöglich sind. Statistisch gesehen ist es ein bisschen hässlich, aber es wird wahrscheinlich die gewünschten Ergebnisse liefern. Natürlich wird eine Verteilung wie "5 4 5 4 5" nicht verhindert. Sie könnten schicker werden und den vorletzten (sagen wir) 60% der Zeit und den drittletzten (sagen wir) 30% ablehnen.

Ich empfehle dies nicht als gutes Spieldesign. Schlagen Sie einfach vor, wie Sie das erreichen, was Sie wollen.


Einige Werte in meinem Spiel, wie z. B. ein kritischer Treffer, können keine Chance von mehr als 50% haben, daher blockiere ich das Wiederholen überhaupt, aber dies verringert die Wahrscheinlichkeit eines Ereignisses für einige Prozent.
Denker

4

Es ist nicht wirklich klar, was Sie wollen. Es ist möglich, eine Funktion so zu erstellen, dass bei den ersten fünf Aufrufen die Nummern 1 bis 5 in zufälliger Reihenfolge zurückgegeben werden.

Aber das ist nicht wirklich zufällig. Der Spieler wird wissen, dass er in den nächsten 5 Angriffen genau eine 5 bekommen wird. Es könnte jedoch das sein, was Sie wollen, und in diesem Fall müssen Sie es einfach selbst codieren. (Erstellen Sie ein Array mit den Zahlen und mischen Sie sie dann.)

Alternativ können Sie Ihren aktuellen Ansatz weiterhin verwenden und davon ausgehen, dass Ihre aktuellen Ergebnisse auf einen schlechten Zufallsgenerator zurückzuführen sind. Beachten Sie, dass mit Ihren aktuellen Nummern möglicherweise nichts falsch ist. Zufällige Werte sind zufällig. Manchmal erhalten Sie 2, 3 oder 8 des gleichen Werts hintereinander. Weil sie zufällig sind. Ein guter Zufallsgenerator garantiert nur, dass im Durchschnitt alle Zahlen gleich oft zurückgegeben werden.

Wenn Sie einen schlechten Zufallsgenerator verwendet haben, hat dies möglicherweise Ihre Ergebnisse verzerrt. Wenn dies der Fall ist, sollte das Problem durch einfaches Wechseln zu einem besseren Zufallsgenerator behoben werden. (Weitere Generatoren finden Sie in der Boost.Random-Bibliothek.)

Alternativ können Sie sich die letzten N Werte merken, die von Ihrer Zufallsfunktion zurückgegeben wurden, und das Ergebnis mit diesen abwägen. (Ein einfaches Beispiel wäre: "Für jedes Auftreten des neuen Ergebnisses besteht eine 50% ige Chance, dass wir den Wert verwerfen und einen neuen erhalten."

Wenn ich raten müsste, würde ich sagen, dass das Festhalten an "tatsächlicher" Zufälligkeit Ihre beste Wahl ist. Stellen Sie sicher, dass Sie einen guten Zufallsgenerator verwenden, und fahren Sie dann so fort, wie Sie es jetzt tun.


Tatsächlich ist die Funktion, die er verwendet, dieselbe wie die beste RNG in der Boost-Bibliothek.
Michael Borgwardt

MT ist nicht das "Beste", das habe ich zuletzt überprüft. Es ist schön, einfach und schnell, aber es liefert nicht die beste Verteilung. Wie auch immer, schnappen Sie sich eine Million Zufallszahlen und überprüfen Sie die Verteilung. Finden Sie heraus, ob Ihre Zufallsfunktion tatsächlich eine gleichmäßige Verteilung ergibt oder nicht. Wenn nicht, finden Sie einen besseren Generator. Wenn dies der Fall ist, saugen Sie es entweder auf und akzeptieren Sie die gelegentliche Reihe von kritischen Punkten oder betrügen Sie und machen Sie die Ergebnisse weniger zufällig und vorhersehbarer.
Jalf

4

Sie können eine Liste mit den Zahlen 1 bis 5 erstellen und diese nach Zufälligkeit sortieren lassen. Dann gehen Sie einfach die Liste durch, die Sie erstellt haben. Sie haben die Garantie, mindestens einmal auf jede Zahl zu stoßen ... Wenn Sie mit den ersten 5 fertig sind, erstellen Sie einfach weitere 5 Zahlen ...


4

Ich empfehle ein progressives prozentuales System, wie es Blizzard verwendet: http://www.shacknews.com/onearticle.x/57886

Im Allgemeinen würfeln Sie ein RNG und vergleichen es dann mit einem Wert, um festzustellen, ob dies erfolgreich ist oder nicht. Das könnte so aussehen:

if ( randNumber <= .2 ) {
   //Critical
} else {
   //Normal
}

Alles, was Sie tun müssen, ist eine schrittweise Erhöhung der Basischance hinzuzufügen ...

if (randNumber <= .2 + progressiveChance ) {
   progressiveChance = 0;
   //Critical
} else {
   progressiveChance += CHANCE_MODIFIER;
   //Normal hit
}

Wenn Sie es brauchen, um ausgefallener zu sein, ist es ziemlich einfach, mehr hinzuzufügen. Sie können den Betrag, den progressiveChance erhalten kann, begrenzen, um eine 100% ige kritische Chance zu vermeiden, oder ihn bei bestimmten Ereignissen zurücksetzen. Sie können progressiveChance auch in kleineren Beträgen mit jedem Boost mit etwas wie progressiveChance + = (1 - progressiveChance) * SCALE erhöhen, wobei SCALE <1 ist.


4

Wenn Sie sich ein wenig mit Mathematik beschäftigen, können Sie wahrscheinlich die Exponentialverteilung ausprobieren

Wenn zum Beispiel Lambda = 0,5 ist, ist der erwartete Wert 2 (lesen Sie diesen Artikel!), Was bedeutet, dass Sie höchstwahrscheinlich jede zweite Runde / krit / was auch immer treffen werden (wie 50%, oder?). Aber mit einer solchen Wahrscheinlichkeitsverteilung werden Sie in der 0. Runde (in der das Ereignis bereits eingetreten war und turn_counter zurückgesetzt wurde) definitiv eine Chance von 40% haben, die nächste Runde zu treffen, ungefähr 65%. Chance, es in der 2. Runde (nächste nach der nächsten) zu machen, ungefähr 80%, um die 3. Runde zu treffen und so weiter.

Der gesamte Zweck dieser Verteilung besteht darin, dass jemand, der eine Trefferchance von 50% hat und dreimal hintereinander verfehlt, einen sicheren Treffer erzielt (also eine Chance von über 80%, die sich in jeder nächsten Runde erhöht). Dies führt zu "faireren" Ergebnissen, wobei die Wahrscheinlichkeit von über 50% unverändert bleibt.

Wenn Sie Ihre 20% ige Chance auf Kritik nutzen, haben Sie

  • 17% zum kritischen 1. Zug
  • 32% zum kritischen 2. Zug, wenn in allen vorherigen keine kritischen Punkte auftreten.
  • 45% zum kritischen 3. Zug, wenn in allen vorherigen keine kritischen Punkte auftreten.
  • 54% zum kritischen 4. Zug, wenn in allen vorherigen keine kritischen Punkte auftreten.
  • ...
  • 80% zum kritischen 8. Zug, wenn in allen vorherigen keine kritischen Punkte auftreten.

Es besteht immer noch eine Chance von 0,2% (gegenüber diesen 5%), dass 3 kritische Treffer + 2 nicht kritische Treffer in 5 aufeinanderfolgenden Runden erzielt werden. Und es gibt eine 14% ige Chance für 4 aufeinanderfolgende Nichtkritiker, 5% von 5, 1,5% für 6, 0,3% für 7, 0,07% für 8 aufeinanderfolgende Nichtkritiker. Ich wette, es ist "fairer" als 41%, 32%, 26%, 21% und 16%.

Ich hoffe, Sie langweilen sich immer noch nicht zu Tode.


Dies ist meiner Lösung ziemlich ähnlich, außer dass sie sich nur an die Zeit seit dem letzten kritischen Treffer "erinnert". Bei dieser Lösung entspricht eine Folge von 4 kritischen Treffern hinsichtlich der Wahrscheinlichkeiten für die Zukunft einer Folge von 1 kritischen Treffern. Wenn kritische Treffer gut sind, begrenzt diese Lösung Ihr Abwärtsrisiko, nicht jedoch Ihr Aufwärtsrisiko. Meine Lösung betrifft beide.
Neil G

Es ist offensichtlich, dass verschiedene Lösungen ihre eigenen Vorteile haben. Dieser konzentriert sich darauf, die Zufälligkeit aus wissenschaftlicher Sicht sauber zu halten. Es bedeutet nicht, dass es irgendwie besser ist, als eine Tasche oder irgendetwas anderes zu mischen. Es ist nur eine Lösung, die es wert ist, ausprobiert zu werden.
Dunkel

3

Was ist mit der Chance, kritisch zu werden, abhängig von den letzten N Angriffen? Ein einfaches Schema ist eine Art Markov-Kette: http://en.wikipedia.org/wiki/Markov_chain, aber der Code ist trotzdem sehr einfach.


IF turns_since_last_critical < M THEN 
   critial = false
   turns_since_last_critical++;
ELSE
   critial = IsCritical(chance);
   IF Critial THEN
       turns_since_last_critica = 0;
   ELSE
       turns_since_last_critica++;
   END IF;
END IF;

Natürlich müssen Sie Ihre Mathematik machen, da die Chance eines Kritikers geringer ist als die Chance eines Kritischen, wenn Sie wissen, dass es seit dem letzten Mal genug Runden gegeben hat


Sie erzielen den größten Teil des Effekts, wenn Sie nur den letzten Angriff berücksichtigen. Sei P die beobachtete Trefferquote, R die Trefferquote nach einem Fehlschlag und R / 2 die Trefferquote nach einem Treffer. Per Definition haben Sie dann zu jedem Zeitpunkt die Chance, P = P * R + (1-P) * (R / 2) zu treffen. Dies bedeutet P = R / (2-R)
MSalters

2

OP,

Ziemlich genau, wenn Sie wollen, dass es fair ist, wird es nicht zufällig sein.

Das Problem Ihres Spiels ist die tatsächliche Spieldauer. Je länger die Übereinstimmung ist, desto weniger Zufälligkeit werden Sie sehen (kritische Treffer sind in der Regel 20%) und es wird sich Ihren beabsichtigten Werten nähern.

Sie haben zwei Möglichkeiten: Berechnen Sie die Angriffe anhand der vorherigen Würfe vor. Sie erhalten alle 5 Angriffe einen kritischen Treffer (basierend auf Ihren 20%), aber Sie können die Reihenfolge, in der er auftritt, zufällig festlegen.

listOfFollowingAttacks = {Hit, Hit, Hit, Miss, Crit};

Das ist das Muster, das Sie wollen. Lassen Sie es also zufällig aus dieser Liste auswählen, bis es leer ist. Sie erstellen es neu.

Das ist ein Muster, das ich für mein Spiel erstellt habe. Es funktioniert ganz gut für das, was ich möchte.

Ihre zweite Option wäre, die Chance auf Kritik zu erhöhen. Am Ende aller Angriffe werden Sie wahrscheinlich eine gleichmäßigere Zahl sehen (vorausgesetzt, Ihre Spiele enden ziemlich schnell). Je weniger% Chance, desto mehr RNG würden Sie bekommen.


2

Sie betrachten eine lineare Verteilung, wenn Sie wahrscheinlich eine Normalverteilung wünschen.

Wenn Sie sich daran erinnern, dass Sie in Ihrer Jugend D & D gespielt haben, wurden Sie gebeten, mehrere n-seitige Würfel zu werfen und dann die Ergebnisse zu summieren.

Zum Beispiel unterscheidet sich das Würfeln von 4 x 6-seitigen Würfeln vom Würfeln von 1 x 24-seitigen Würfeln.


2

City of Heroes hat tatsächlich einen Mechaniker namens "Streakbreaker", der genau dieses Problem löst. Die Funktionsweise besteht darin, dass nach einer Reihe von Fehlern mit einer Länge, die sich auf die niedrigste Trefferwahrscheinlichkeit in der Reihe bezieht, der nächste Angriff garantiert ein Treffer ist. Wenn Sie beispielsweise einen Angriff mit über 90% verpassen, um die Chance zu treffen, wird Ihr nächster Angriff automatisch getroffen. Wenn Ihre Trefferchance jedoch um 60% niedriger ist, müssen Sie mehrere aufeinanderfolgende Fehlschläge ausführen, um den "Streifenbrecher" auszulösen (I. kenne die genauen Zahlen nicht)



0

Wie wäre es mit einer Gewichtung des Wertes?

Wenn Sie beispielsweise eine 20% ige Chance auf einen kritischen Treffer haben, generieren Sie eine Zahl zwischen 1 und 5, wobei eine Zahl einen kritischen Treffer darstellt, oder eine Zahl zwischen 1 und 100, wobei 20 Zahlen ein kritischer Treffer sind.

Solange Sie jedoch mit Zufalls- oder Pseudozufallszahlen arbeiten, können Sie die aktuell angezeigten Ergebnisse möglicherweise nicht vermeiden. Es liegt in der Natur der Zufälligkeit.


Und warum sollte das einen Unterschied machen? Es besteht eine genau gleiche Chance, für beide Zahlengruppen einen kritischen Wert zu erhalten.
Samjudson

Genau. Ich präsentiere ihm nur zwei Optionen für sein 20% -Beispiel. Obwohl 100 wahrscheinlich besser funktionieren würde, wenn Sie mit Prozentsätzen ganzer Zahlen arbeiten, da Sie nur einen "Würfel" simulieren müssten, wenn Sie so darüber nachdenken möchten.
Thomas Owens

Die Optionen, die Sie präsentieren, sind genau das, was er bereits tut.
Ceejayoz

2
Nicht für das, was er will. Er möchte einen Generator für nicht zufällige Zahlen, auch wenn er glaubt, dass dies ein Zufallsgenerator ist.
Ceejayoz

0

Reaktion auf: "Das Problem ist, dass ich sehr schlechte Ergebnisse im wirklichen Leben erzielt habe - manchmal erhalten Spieler 3 kritische Treffer in 5 Treffern, manchmal keine in 15 Treffern."

Sie haben eine Chance zwischen 3 und 4%, in 15 Treffern nichts zu bekommen ...


Wenn 3500 Spieler in einer Minute 10000 Schlachten online führen, ist ein Problem, das in 3% der Schlachten auftritt, ein sehr häufiges Problem.
Denker

Andererseits ist Pech, das in 3% der Schlachten auftritt, immer noch nur Pech.
MSalters

0

Ich würde den folgenden "zufällig verzögerten Putback-Würfel" vorschlagen:

  • Behalten Sie zwei Arrays bei, von denen eines ( in-array) anfänglich mit den Werten von 0 bis n-1 gefüllt ist und das andere ( out-array) leer ist
  • Wenn ein Ergebnis angefordert wird:
    • Gibt einen zufälligen Wert aus allen definierten Werten in zurückin-array
    • Verschieben Sie diesen Wert von in-arraynachout-array
    • Verschieben Sie ein zufälliges Element (über alle Elemente, einschließlich des undefinierten!) Elements von out-arrayzurück nachin-array

Dies hat die Eigenschaft, dass es langsamer "reagiert", je größer n ist. Wenn Sie beispielsweise eine Chance von 20% wünschen, ist das Setzen von n auf 5 und das Schlagen auf eine 0 "weniger zufällig" als das Setzen von n auf 10 und das Schlagen auf eine 0 oder 1, und es wird fast 0 bis 199 von 1000 sein nicht von wahrer Zufälligkeit über eine kleine Stichprobe zu unterscheiden. Sie müssen n an Ihre Stichprobengröße anpassen .


0

Berechnen Sie für jeden Spieler einen zufälligen kritischen Treffer vor .

// OBJECT
//...
// OnAttack()
//...
c_h = c_h -1;
if ( c_h == 0 ) {
 // Yes, critical hit!
 c_h = random(5) + 1 // for the next time
 // ...
}

0

Ich denke, vielleicht verwenden Sie die falsche Zufallsverteilungsfunktion. Sie möchten wahrscheinlich keine gleichmäßige Verteilung über die Zahlen. Versuchen Sie stattdessen eine Normalverteilung, damit die kritischen Treffer ungewöhnlicher werden als die "normalen" Treffer.

Ich arbeite mit Java, daher bin ich mir nicht sicher, wo Sie etwas für C ++ finden können, das Ihnen Zufallszahlen mit einer normalen Verteilung gibt, aber es muss etwas da draußen geben.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.