Ich bin gerade dabei, ein neues einfaches Spiel für Handys zu erstellen, und habe mehrere Tage mit dem folgenden Teil verbracht.
Nehmen wir zur Vereinfachung an, ich habe zwei Kämpfer. Das einzige Attribut von ihnen ist Angriff und Verteidigung. Bei den ersten Angriffen kommt es nur auf den Angriff und die Verteidigung des Gegners an. Und umgekehrt.
Sie haben keine Ausrüstung, Gegenstände, Ausdauer oder Gesundheit. Nur Angriff gegen Verteidigung.
Beispiel:
Kämpfer 1:
Angriff: 50, Verteidigung: 35
Kämpfer 2:
Angriff 20, Verteidigung: 80
Der Kampfprozess wird nur ein einziger Angriff sein, der den Gewinner bestimmt. Also keine Mehrfachangriffe oder Runden. Ich möchte es nicht deterministisch machen, sondern eine leichte Version von Unerwartetem hinzufügen. Ein Kämpfer mit geringerem Angriff kann einen anderen Kämpfer mit höherer Verteidigung gewinnen (aber natürlich nicht jedes Mal)
Meine erste Idee war, es linear zu machen und einen einheitlichen Zufallszahlengenerator aufzurufen.
If Random() < att1 / (att1 + def2) {
winner = fighter1
} else {
winner = fighter2
}
Beispiel: Angriff 50 und Verteidigung 80: Der angreifende Kämpfer hat ungefähr 38% zu gewinnen. Es scheint mir jedoch, dass das Unerwartete zu weit ist und die schlimmsten Kämpfer viel gewinnen werden.
Ich habe mich gefragt, wie Sie an ähnlichen Situationen gearbeitet haben.
PS Ich habe in dieser QnA und anderen Quellen viel gesucht und ähnliche Fragen gefunden, die für SE als zu weit gefasst bezeichnet wurden. Aber diese hatten viele Attribute, Waffen, Gegenstände, Klassen usw., die es zu kompliziert machen könnten. Ich denke, meine Version ist viel einfacher, um sie in den QnA-Stil der SE zu integrieren.
Antworten:
Wenn Sie möchten, dass Ihre Kampfergebnisse vorhersehbarer, aber nicht vollständig deterministisch sind, haben Sie das Beste aus n System verwenden.
Wiederholen Sie die Kampfzeiten
n
(wobein
eine ungerade Zahl sein sollte) und erklären Sie den Kämpfer zum Sieger, der häufiger gewonnen hat. Je höher Ihr Wert fürn
die weniger überraschenden Gewinne und Verluste, die Sie haben werden.Dieses System funktioniert nur in dem speziellen Fall, in dem ein Kampf ein einfaches binäres Ergebnis von Gewinn oder Verlust ist. Wenn ein Kampf komplexere Ergebnisse hat, z. B. wenn der Gewinner immer noch einige Trefferpunkte verliert, je nachdem, wie knapp der Gewinn war, funktioniert dieser Ansatz nicht mehr. Eine allgemeinere Lösung besteht darin, die Art und Weise zu ändern, in der Sie Zufallszahlen generieren. Wenn Sie mehrere Zufallszahlen generieren und dann den Durchschnitt ermitteln, werden die Ergebnisse nahe der Mitte des Bereichs gruppiert und extremere Ergebnisse sind seltener. Beispielsweise:
wird eine Verteilungskurve wie folgt haben:
(Bild mit freundlicher Genehmigung von anydice - ein wirklich nützliches Werkzeug zum Entwerfen von Spielmechanikformeln, die Zufälligkeit beinhalten, nicht nur für Tabletop-Spiele)
In meinem aktuellen Projekt verwende ich eine Hilfsfunktion, mit der eine beliebige Stichprobengröße festgelegt werden kann:
quelle
+
anstelle von verwenden,*
oder ich habe falsch verstanden, was es tut?Dies ist, was ich verwendet habe, um den Gewinner eines Kampfes in meinem Lords of Conquest Imitator-Applet zu bestimmen. In diesem Spiel gibt es ähnlich wie in Ihrer Situation nur einen Angriffswert und einen Verteidigungswert. Die Wahrscheinlichkeit, dass der Angreifer gewinnt, ist umso größer, je mehr Punkte der Angreifer hat und je weniger Punkte die Verteidigung hat. Bei gleichen Werten ergibt sich eine 50% ige Chance, dass der Angriff erfolgreich ist.
Algorithmus
Wirf eine zufällige Münze.
1a. Köpfe: Verteidigung verliert einen Punkt.
1b. Schwänze: Köpfe verlieren einen Punkt.
Wenn sowohl die Verteidigung als auch der Angreifer noch Punkte haben, fahren Sie mit Schritt 1 fort.
Wer 0 Punkte hat, verliert den Kampf.
3a. Angreifer auf 0: Angriff fehlgeschlagen.
3b. Verteidigung bis 0: Angriff erfolgreich.
Ich habe es in Java geschrieben, aber es sollte leicht in andere Sprachen übersetzbar sein.
Ein Beispiel
Angenommen, att = 2 und def = 2, um sicherzustellen, dass die Wahrscheinlichkeit 50% beträgt.
Der Kampf wird in maximal zwei
n = att + def - 1
Münzwürfen oder 3 in diesem Beispiel entschieden (hier ist es im Wesentlichen das Beste aus 3). Es gibt 2 n mögliche Kombinationen von Münzwürfen. Hier bedeutet "W", dass der Angreifer den Münzwurf gewonnen hat, und "L" bedeutet, dass der Angreifer den Münzwurf verloren hat.Der Angreifer gewinnt in 4/8 oder 50% der Fälle.
Die Mathematik
Die mathematischen Wahrscheinlichkeiten, die sich aus diesem einfachen Algorithmus ergeben, sind komplizierter als der Algorithmus selbst.
Die Anzahl der Kombinationen, bei denen genau x Ls vorhanden sind, ergibt sich aus der Kombinationsfunktion:
Der Angreifer gewinnt, wenn zwischen
0
undatt - 1
Ls liegen. Die Anzahl der Gewinnkombinationen entspricht der Summe der Kombinationen von0
bisatt - 1
, einer kumulativen Binomialverteilung:Die Wahrscheinlichkeit des Angreifers zu gewinnen , ist w geteilt durch 2 n , eine kumulative binomische Wahrscheinlichkeit:
Hier ist der Code in Java, um diese Wahrscheinlichkeit für beliebige
att
unddef
Werte zu berechnen :Testcode:
Ausgabe:
Beobachtungen
Die Wahrscheinlichkeiten sind,
0.0
wenn der Angreifer0
Punkte hat,1.0
wenn der Angreifer Punkte hat, aber die Verteidigung0
Punkte hat,0.5
wenn die Punkte gleich sind, weniger als0.5
wenn der Angreifer weniger Punkte als die Verteidigung hat und größer als0.5
wenn der Angreifer mehr Punkte als die Verteidigung hat .Mit
att = 50
unddef = 80
musste ich aufBigDecimal
s umschalten, um einen Überlauf zu vermeiden, aber ich erhalte eine Wahrscheinlichkeit von etwa 0,0040.Sie können die Wahrscheinlichkeit näher an 0,5 bringen, indem Sie den
att
Wert so ändern , dass er der Durchschnitt der Werteatt
unddef
ist. Att = 50, Def = 80 wird (65, 80), was eine Wahrscheinlichkeit von 0,1056 ergibt.quelle
Sie können den Angriff durch eine Zufallszahl ändern, die aus einer Normalverteilung stammt. Auf diese Weise wird das Ergebnis meistens das sein, was Sie erwarten, aber gelegentlich verliert ein höherer Angriff gegen eine niedrigere Verteidigung oder ein niedrigerer Angriff gewinnt gegen eine höhere Verteidigung. Die Wahrscheinlichkeit, dass dies geschieht, wird geringer, wenn der Unterschied zwischen Angriff und Verteidigung zunimmt.
Die Funktion
norm(x0, sigma)
gibt einen Float zurück, der aus einer bei x0 zentrierten Normalverteilung mit Standardabweichung Sigma abgetastet wurde. Die meisten Programmiersprachen bieten eine Bibliothek mit einer solchen Funktion. Wenn Sie sie jedoch selbst erstellen möchten, schauen Sie sich diese Frage an . Sie müssten Sigma so einstellen, dass es sich „richtig anfühlt“, aber ein Wert von 10-20 könnte ein guter Anfang sein.Für einige Sigma-Werte
att1 - def2
sieht die Wahrscheinlichkeit eines Sieges für einen bestimmten so aus:quelle