C'est ce que j'ai utilisé pour déterminer le vainqueur d'une bataille dans mon applet Lords of Conquest Imitator. Dans ce jeu, similaire à votre situation, il n'y a qu'une valeur d'attaque et une valeur de défense. La probabilité que l'attaquant gagne est plus grande plus l'attaquant a de points et moins la défense a de points, avec des valeurs égales évaluant à 50% de chances de réussite de l'attaque.
Algorithme
Lancez une pièce au hasard.
1a. Têtes: la défense perd un point.
1b. Queues: les têtes perdent un point.
Si la défense et l'attaquant ont encore des points, revenez à l'étape 1.
Celui qui est à 0 point perd la bataille.
3a. Attaquant jusqu'à 0: l'attaque échoue.
3b. Défense jusqu'à 0: l'attaque réussit.
Je l'ai écrit en Java, mais il devrait être facilement traduisible dans d'autres langues.
Random rnd = new Random();
while (att > 0 && def > 0)
{
if (rnd.nextDouble() < 0.5)
def--;
else
att--;
}
boolean attackSucceeds = att > 0;
Un exemple
Par exemple, disons que att = 2 et def = 2, juste pour s'assurer que la probabilité est de 50%.
La bataille sera décidée en un maximum de n = att + def - 1
lancers de pièces, ou 3 dans cet exemple (c'est essentiellement le meilleur des 3 ici). Il y a 2 n combinaisons possibles de lancer de pièces. Ici, "W" signifie que l'attaquant a gagné le lancer de pièces et "L" signifie que l'attaquant a perdu le lancer de pièces.
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
L'attaquant gagne dans 4/8, soit 50% des cas.
Les maths
Les probabilités mathématiques résultant de cet algorithme simple sont plus compliquées que l'algorithme lui-même.
Le nombre de combinaisons où il y a exactement x Ls est donné par la fonction de combinaison:
C(n, x) = n! / (x! * (n - x)!)
L'attaquant gagne lorsqu'il y a entre 0
et att - 1
Ls. Le nombre de combinaisons gagnantes est égal à la somme des combinaisons de à 0
travers att - 1
, une distribution binomiale cumulative:
(att - 1)
w = Σ C(n, x)
x = 0
La probabilité que l'attaquant gagne est w divisée par 2 n , une probabilité cumulée binomiale:
p = w / 2^n
Voici le code en Java pour calculer cette probabilité d'arbitraire att
et de def
valeurs:
/**
* 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;
}
Code de test:
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));
}
Production:
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
Observations
Les probabilités sont 0.0
si l'attaquant a des 0
points, 1.0
si l'attaquant a des points mais la défense a des 0
points, 0.5
si les points sont égaux, moins que 0.5
si l'attaquant a moins de points que la défense, et plus grand que 0.5
si l'attaquant a plus de points que la défense .
En prenant att = 50
et def = 80
, je devais passer à BigDecimal
s pour éviter un débordement, mais j'obtiens une probabilité d'environ 0,0040.
Vous pouvez rapprocher la probabilité de 0,5 en modifiant la att
valeur pour qu'elle soit la moyenne des valeurs att
et def
. Att = 50, Def = 80 devient (65, 80), ce qui donne une probabilité de 0,1056.