#include #include #define myrand(range) (1+(int) (range*rand()/(RAND_MAX+1.0))) #define CALLS 1000 #define ERROR 10 #define CORRECTION 1 double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp); double win_chance_approx(int as, int ahp, int afp, int ds, int dhp, int dfp); int main() { int i, j; int count = 0, fail = 0; int as, ahp, afp, ds, dhp, dfp; double prob, prob_app; /* for (i = 0; i < CALLS; i++){ as = myrand(10.0); ds = myrand(10.0); ahp = myrand(6.0) * 10; dhp = myrand(6.0) * 10; afp = myrand(2.0); dfp = myrand(2.0); */ for(as = 1; as < 16; as++){ for(ds = 1; ds < as+1; ds++){ for(afp = 1; afp < 3; afp++) { for(dfp = 1; dfp < 3; dfp++) { for(i = 1; i < 5; i++){ for(j = 1; j < 5; j++){ ahp = i*10; dhp = j*10; count++; prob = win_chance(as, ahp, afp, ds, dhp, dfp); prob_app = win_chance_approx(as, ahp, afp, ds, dhp, dfp); if (fabs(100*(prob - prob_app)) > ERROR) { fail++; printf("Stats Attacker: Strength %d, HP %d, FP %d \n", as, ahp, afp); printf("Stats Defender: Strength %d, HP %d, FP %d \n", ds, dhp, dfp); printf("True prob: %f, approximmation %f," "abs error %f percents\n\n", prob, prob_app, 100*(prob - prob_app)); } } } } } } } printf("%d out of %d tries FAILED\n", fail, count); } /*********************************************************************** 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(...) NOTE: this number can be _very_ small, fx in a battle between an ironclad and a battleship the ironclad has less than 1/100000 chance of winning. 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 win_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 - 1) / dfp; int def_N_lose = (dhp + afp - 1) / afp; /* Probability of losing one round */ double att_P_lose1 = (as + ds == 0) ? 0.5 : (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. */ double binom_save = pow(def_P_lose1, (double)(def_N_lose - 1)); double accum_prob = binom_save; /* lr = 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; 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; } double win_chance_approx(int as, int ahp, int afp, int ds, int dhp, int dfp) { /* Rating of the attacker */ int attack_rating = as * ahp * afp; /* Rating of the defender */ int defense_rating = ds * dhp * dfp; /* Ratio of the ratings */ double rat = defense_rating / ((double) attack_rating); /* double answer = pow(rat, 5); */ double answer; if (CORRECTION && fabs(rat - .6666666) < .17 && ahp < 16*dfp) { rat += dfp * rat / ((double) ahp); } answer = rat*rat; answer *= answer * rat; answer = 1 / (1 + answer); return answer; }