#include /*********************************************************************** Returns the chance of the attacker winning, a number between 0 and 1. If you want the chance that the defender wins just use 1-chance(...) The algoritm calculates the probability of each possible number of HP's the attacker has left. Maybe that info should be preserved for use in the AI. ***********************************************************************/ double chance(int as, int ahp, int afp, int ds, int dhp, int dfp) { /* number of rounds a unit can fight without dying */ int att_N_lose = ahp/dfp + ahp%dfp; int def_N_lose = dhp/afp + dhp%afp; /* Probability of losing one round */ double att_P_lose1 = (double) ds / (as + ds); double def_P_lose1 = 1 - att_P_lose1; /* This calculates binomial_coeff(def_N_lose-1 + lr, lr) * def_P_lose1^(def_N_lose-1) * att_P_lose1^(lr) * def_P_lose1 for each possible number of rounds lost (rl) by the winning unit. rl is of course less than the number of rounds the winning unit should lose to lose all it's hit points. The probabilities are then summed. To see this is correct consider the set of series for all valid fights. These series are the type (win, lose, lose...). The possible lenghts are def_N_lose to def_N_lose+att_N_lose-1. A series is not valid unless it contains def_N_lose wins, and one of the wins must be the last one, or the series would be equivalent the a shorter series (the attacker would have won one or more fights previously). So since the last fight is a win we disregard it while calculating. Now a series contains def_N_lose-1 wins. So for each possible lenght of a series we find the probability of every valid series and then sum. For a specific lenght (a "lr") every series have the probability def_P_lose1^(def_N_lose-1) * att_P_lose1^(lr) and then getting from that to the real series requires a win, ie factor def_N_lose. The number of series with lenght (def_N_lose-1 + lr) and "lr" lost fights is binomial_coeff(def_N_lose-1 + lr, lr) And by multiplying we get the formula on the top of this code block. Adding the cumulative probability for each valid lenght then gives the total probability. We clearly have all valid series this way. To see that we have counted none twice note that would require a series with a smaller series inbedded. But since the smaller series already included def_N_lose wins, and the larger series ends with a win, it would have too many wins and therefore cannot exist. In practice each binomial coefficient for a series lenght can be calculated from the previous. In the coefficient (n, k) n is increased and k is unchanged. The "* def_P_lose1" is multiplied on the sum afterwards. (lots of talk for so little code) */ double binom_save = pow(def_P_lose1, def_N_lose - 1); double accum_prob = binom_save; /* rl = 0 */ int lr; /* the number of Lost Rounds by the attacker */ for (lr = 1; lr < att_N_lose; lr++) { /* update the coefficient */ int n = lr + def_N_lose - 1; binom_save *= n; binom_save /= (lr - 2); /* n - def_N_lose - 1 */ binom_save *= att_P_lose1; /* use it for this lr */ accum_prob += binom_save; } /* Every element of the sum needs a factor for the very last fight round */ accum_prob *= def_P_lose1; return accum_prob; } int main(int argc, char **argv) { int args[6]; int i; if (argc != 7) { printf("6 args!\n"); /* +1 for command... */ return 0; } for (i=0; i < 6; i++) sscanf(argv[i+1], "%d", &args[i]); printf("win chance: %f\n", chance(args[0], args[1], args[2], args[3], args[4], args[5])); return 1; }