Esto es lo que solía determinar el ganador de una batalla en mi applet Imitator de Lords of Conquest. En este juego, similar a tu situación, solo hay un valor de ataque y un valor de defensa. La probabilidad de que el atacante gane es mayor cuantos más puntos tenga el atacante, y menos puntos tenga la defensa, con valores iguales que evalúan un 50% de probabilidad de que el ataque tenga éxito.
Algoritmo
Lanza una moneda al azar.
1a. Jefes: la defensa pierde un punto.
1b. Colas: las cabezas pierden un punto.
Si tanto la defensa como el atacante aún tienen puntos, regrese al paso 1.
Quien tenga 0 puntos pierde la batalla.
3a. Atacante hasta 0: el ataque falla.
3b. Defensa hasta 0: el ataque tiene éxito.
Lo escribí en Java, pero debería ser fácilmente traducible a otros idiomas.
Random rnd = new Random();
while (att > 0 && def > 0)
{
if (rnd.nextDouble() < 0.5)
def--;
else
att--;
}
boolean attackSucceeds = att > 0;
Un ejemplo
Por ejemplo, supongamos que att = 2 y def = 2, solo para asegurarse de que la probabilidad sea del 50%.
La batalla se decidirá en un máximo de n = att + def - 1lanzamientos de monedas, o 3 en este ejemplo (es esencialmente el mejor de 3 aquí). Hay 2 n combinaciones posibles de lanzamientos de monedas. Aquí, "W" significa que el atacante ganó el lanzamiento de la moneda, y "L" significa que el atacante perdió el lanzamiento de la moneda.
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
El atacante gana en 4/8, o 50% de los casos.
Las matemáticas
Las probabilidades matemáticas que surgen de este algoritmo simple son más complicadas que el algoritmo mismo.
El número de combinaciones donde exactamente x Ls viene dado por la función de combinación:
C(n, x) = n! / (x! * (n - x)!)
El atacante gana cuando hay entre 0y att - 1Ls. El número de combinaciones ganadoras es igual a la suma de combinaciones de a 0través att - 1, una distribución binomial acumulativa:
(att - 1)
w = Σ C(n, x)
x = 0
La probabilidad de que el atacante ganadora es w divide por 2 n , una probabilidad acumulativa binomial:
p = w / 2^n
Aquí está el código en Java para calcular esta probabilidad para valores arbitrarios atty def:
/**
* 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;
}
Código de prueba:
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));
}
Salida:
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
Observaciones
Las probabilidades son 0.0si el atacante tiene 0puntos, 1.0si el atacante tiene puntos pero la defensa tiene 0puntos, 0.5si los puntos son iguales, menos que 0.5si el atacante tiene menos puntos que la defensa, y mayores que 0.5si el atacante tiene más puntos que la defensa .
Tomando att = 50y def = 80, necesitaba cambiar a BigDecimals para evitar el desbordamiento, pero tengo una probabilidad de aproximadamente 0.0040.
Puede acercar la probabilidad a 0,5 cambiando el attvalor para que sea el promedio de los valores atty def. Att = 50, Def = 80 se convierte en (65, 80), lo que arroja una probabilidad de 0.1056.