Це те, що я використовував для визначення переможця битви в моєму аплеті «Імітатор Господарів». У цій грі, аналогічній вашій ситуації, є лише значення атаки та захисне значення. Вірогідність того, що нападник виграє, тим більше, чим більше очок має нападник, і чим менше, тим більше очок має захист, при рівних значеннях, що оцінюють 50% шанс успіху атаки.
Алгоритм
Переверніть випадкову монету.
1а. Глави: захист втрачає очко.
1б. Хвости: голови втрачають крапку.
Якщо у оборонців та у нападника все ще є очки, поверніться до кроку 1.
Хто знизився до 0 очок, програє битву.
3а. Нападник знижується до 0: Атака не вдається.
3б. Захист до 0: Атака вдається.
Я написав це на Java, але це має бути легко перекладене на інші мови.
Random rnd = new Random();
while (att > 0 && def > 0)
{
if (rnd.nextDouble() < 0.5)
def--;
else
att--;
}
boolean attackSucceeds = att > 0;
Приклад
Наприклад, скажімо, що att = 2 і def = 2, просто щоб переконатися, що ймовірність дорівнює 50%.
Бій вирішуватиметься максимум n = att + def - 1
обертів монети, або 3 у цьому прикладі (це, по суті, найкраще з 3 тут). Можливі 2 n можливих комбінацій гортання монети. Тут "W" означає, що зловмисник виграв монету, а "L" означає, що зловмисник програв монету.
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
Зловмисник виграє в 4/8, або 50% випадків.
Математика
Математичні ймовірності, що виникають із цього простого алгоритму, складніші, ніж сам алгоритм.
Кількість комбінацій, де саме x Ls, задається функцією комбінування:
C(n, x) = n! / (x! * (n - x)!)
Зловмисник виграє, коли є між 0
та att - 1
Ls. Кількість виграшних комбінацій дорівнює сумі комбінацій від 0
наскрізного att - 1
, кумулятивного біноміального розподілу:
(att - 1)
w = Σ C(n, x)
x = 0
Імовірність виграшу зловмисника w ділиться на 2 n , кумулятивна біноміальна ймовірність:
p = w / 2^n
Ось код на Java для обчислення цієї ймовірності для довільних att
і 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;
}
Код тестування:
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));
}
Вихід:
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
Спостереження
Ймовірність полягає в тому 0.0
випадку , якщо нападник має 0
очки, 1.0
якщо нападник має очки, але захист має 0
очки, 0.5
якщо очки рівні, менші, ніж 0.5
якщо нападник має менше очок, ніж захист, і більший, ніж 0.5
якщо у нападника більше очок, ніж у захисту .
Приймаючи att = 50
і def = 80
, мені потрібно було перейти на BigDecimal
s, щоб уникнути переповнення, але я отримую ймовірність приблизно 0,0040.
Ви можете наблизити ймовірність до 0,5, змінивши att
значення на середнє значення att
та def
значення. Att = 50, Def = 80 стає (65, 80), що дає ймовірність 0,1056.