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.
Random rnd = new Random();
while (att > 0 && def > 0)
{
if (rnd.nextDouble() < 0.5)
def--;
else
att--;
}
boolean attackSucceeds = att > 0;
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.
L,L,L - Attacker loses
L,L,W - Attacker loses
L,W,L - Attacker loses
L,W,W - Attacker wins
W,L,L - Attacker loses
W,L,W - Attacker wins
W,W,L - Attacker wins
W,W,W - Attacker wins
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:
C(n, x) = n! / (x! * (n - x)!)
Der Angreifer gewinnt, wenn zwischen 0
und att - 1
Ls liegen. Die Anzahl der Gewinnkombinationen entspricht der Summe der Kombinationen von 0
bis att - 1
, einer kumulativen Binomialverteilung:
(att - 1)
w = Σ C(n, x)
x = 0
Die Wahrscheinlichkeit des Angreifers zu gewinnen , ist w geteilt durch 2 n , eine kumulative binomische Wahrscheinlichkeit:
p = w / 2^n
Hier ist der Code in Java, um diese Wahrscheinlichkeit für beliebige att
und def
Werte zu berechnen :
/**
* Returns the probability of the attacker winning.
* @param att The attacker's points.
* @param def The defense's points.
* @return The probability of the attacker winning, between 0.0 and 1.0.
*/
public static double probWin(int att, int def)
{
long w = 0;
int n = att + def - 1;
if (n < 0)
return Double.NaN;
for (int i = 0; i < att; i++)
w += combination(n, i);
return (double) w / (1 << n);
}
/**
* Computes C(n, k) = n! / (k! * (n - k)!)
* @param n The number of possibilities.
* @param k The number of choices.
* @return The combination.
*/
public static long combination(int n, int k)
{
long c = 1;
for (long i = n; i > n - k; i--)
c *= i;
for (long i = 2; i <= k; i++)
c /= i;
return c;
}
Testcode:
public static void main(String[] args)
{
for (int n = 0; n < 10; n++)
for (int k = 0; k <= n; k++)
System.out.println("C(" + n + ", " + k + ") = " + combination(n, k));
for (int att = 0; att < 5; att++)
for (int def = 0; def < 10; def++)
System.out.println("att: " + att + ", def: " + def + "; prob: " + probWin(att, def));
}
Ausgabe:
att: 0, def: 0; prob: NaN
att: 0, def: 1; prob: 0.0
att: 0, def: 2; prob: 0.0
att: 0, def: 3; prob: 0.0
att: 0, def: 4; prob: 0.0
att: 1, def: 0; prob: 1.0
att: 1, def: 1; prob: 0.5
att: 1, def: 2; prob: 0.25
att: 1, def: 3; prob: 0.125
att: 1, def: 4; prob: 0.0625
att: 1, def: 5; prob: 0.03125
att: 2, def: 0; prob: 1.0
att: 2, def: 1; prob: 0.75
att: 2, def: 2; prob: 0.5
att: 2, def: 3; prob: 0.3125
att: 2, def: 4; prob: 0.1875
att: 2, def: 5; prob: 0.109375
att: 2, def: 6; prob: 0.0625
att: 3, def: 0; prob: 1.0
att: 3, def: 1; prob: 0.875
att: 3, def: 2; prob: 0.6875
att: 3, def: 3; prob: 0.5
att: 3, def: 4; prob: 0.34375
att: 3, def: 5; prob: 0.2265625
att: 3, def: 6; prob: 0.14453125
att: 3, def: 7; prob: 0.08984375
att: 4, def: 0; prob: 1.0
att: 4, def: 1; prob: 0.9375
att: 4, def: 2; prob: 0.8125
att: 4, def: 3; prob: 0.65625
att: 4, def: 4; prob: 0.5
att: 4, def: 5; prob: 0.36328125
att: 4, def: 6; prob: 0.25390625
att: 4, def: 7; prob: 0.171875
att: 4, def: 8; prob: 0.11328125
Beobachtungen
Die Wahrscheinlichkeiten sind, 0.0
wenn der Angreifer 0
Punkte hat, 1.0
wenn der Angreifer Punkte hat, aber die Verteidigung 0
Punkte hat, 0.5
wenn die Punkte gleich sind, weniger als 0.5
wenn der Angreifer weniger Punkte als die Verteidigung hat und größer als 0.5
wenn der Angreifer mehr Punkte als die Verteidigung hat .
Mit att = 50
und def = 80
musste ich auf BigDecimal
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 Werte att
und def
ist. Att = 50, Def = 80 wird (65, 80), was eine Wahrscheinlichkeit von 0,1056 ergibt.