/* civ 3 combat calculator - by vulture (10th Jun 2002) * * Calculates combat result probabilities between 2 units. If one of the units * is able to retreat from combat (fast unit attacking move 1 unit) then * that unit is unit 'A'. Change values in the last block of '#define' * statements to reflect the values of the units you wish to calculate. * Currently set up for veteran cavalry attacking unfortified rifleman on * open ground, both with full hit points. * * You have to work out the terrain modifiers etc. yourself, and use the * correct modified attack/defence values for each unit. It doesn't matter * whether the attacker is unit A or B, UNLESS ONE OF THE UNITS IS RETREAT * CAPABLE - in which case it is unit A regardless of whether it is attacking * or defending. For a cavalry being attacked by an infantry on open ground, * you would use A_STR 3.3, B_STR 6.0 (A's modified defence, B's attack, in * this case). * * The following assumptions are made (based on memory): * * When the fast unit is fighting a unit with only 1 hp left it never tries * to retreat. * * The fast unit only gets 1 chance to retreat. E.g. a cavalry attacking * a rifleman gets reduced to 1 hp while the rifleman still has 3. The * cavalry will try to retreat upon reaching 1 hp. If this fails, the * combat continues. If the cavalry wins the next round, then the rifleman * is on 2 hp, and the cavalry on 1. I assume that the cavalry doesn't get * a second chance to retreat. If it does the calculation gets more complex, * and doesn't make a huge difference to the results (no. of wins decreases * slightly, no. of retreat increases, no. of losses decreases moderately). * * Results are hopefully self explanatory */ #include #include /* don't change these */ #define NO_RETREAT 0 #define CONSCRIPT 1 #define STANDARD 2 #define VETERAN 3 #define ELITE 4 #define MAXLEVEL 5 #define MAXHP 11 /* change these if you have altered the retreat chances in the editor */ #define R_CON 0.34 #define R_STD 0.50 #define R_VET 0.58 #define R_ELI 0.66 /* change these for the units you are interested in (or use command line * options) */ #define HP_A 4 #define HP_B 3 #define A_STR 6.0 #define B_STR 6.6 #define EXPLEVEL VETERAN double fac(int); /* returns factorial of input value */ main(int argc, char *argv[]) { double a_st = A_STR; double b_st = B_STR; double a; double b; int hp_a = HP_A; /* attacker's hit points */ int hp_b = HP_B; /* defender's hit points */ int i, j; /* loop variables */ double coeff, prob; /* used in calculations to store values */ double retreat[MAXLEVEL] = {0.0, R_CON, R_STD, R_VET, R_ELI}; int level; double r = retreat[EXPLEVEL]; /* retreat probability */ double s; /* probability of not retreating */ double p_win = 0.0; double p_retreat = 0.0; double p_lose = 0.0; double array[MAXHP][MAXHP]; for (i = 0; i < MAXHP; i++) { for (j = 0; j < MAXHP; j++) { array[i][j] = 0.0; } } /* deal with command line options */ i = 0; while (++i < argc) { ++(argv[i]); if ((strcmp(argv[i], "A") == 0) || (strcmp(argv[i], "a") == 0)) { j = sscanf(argv[++i], "%lf", &a_st); if (j != 1) { fprintf(stderr, "Can't convert a_st (%s)\n", argv[i]); exit(-1); } j = sscanf(argv[++i], "%d", &hp_a); if (j != 1) { fprintf(stderr, "Can't convert hp_a (%s)\n", argv[i]); exit(-1); } if ((a_st < 0.0) || (hp_a < 1) || (hp_a > MAXHP - 1)) { fprintf(stderr, "Invalid values for unit A\n"); exit(-1); } } else if ((strcmp(argv[i], "B") == 0) || (strcmp(argv[i], "b") == 0)) { j = sscanf(argv[++i], "%lf", &b_st); if (j != 1) { fprintf(stderr, "Can't convert b_st (%s)\n", argv[i]); exit(-1); } j = sscanf(argv[++i], "%d", &hp_b); if (j != 1) { fprintf(stderr, "Can't convert hp_b (%s)\n", argv[i]); exit(-1); } if ((b_st < 0.0) || (hp_b < 1) || (hp_b > MAXHP - 1)) { fprintf(stderr, "Invalid values for unit B\n"); exit(-1); } } else if ((strcmp(argv[i], "R") == 0) || (strcmp(argv[i], "r") == 0)) { j = sscanf(argv[++i], "%lf", &r); if (j != 1) { fprintf(stderr, "Can't convert r (%s)\n", argv[i]); exit(-1); } if ((r < 0.0) || (r > 1.0)) { fprintf(stderr, "Invalid retreat probability (0.0 - 1.0)\n"); exit(-1); } } else if ((strcmp(argv[i], "E") == 0) || (strcmp(argv[i], "e") == 0)) { j = sscanf(argv[++i], "%d", &level); if (j != 1) { fprintf(stderr, "Can't convert level (%s)\n", argv[i]); exit(-1); } if ((level < 0) || (level >= MAXLEVEL)) { fprintf(stderr, "Invalid experience level\n"); exit(-1); } r = retreat[level]; } else if ((strcmp(argv[i], "H") == 0) || (strcmp(argv[i], "h") == 0) || (strcmp(argv[i], "-help") == 0)) { /* help info */ printf("Civ 3 combat probability calculator\n"); printf("Usage information\n\ncommand line options:\n"); printf("\nTo specify combat strengths of units\n"); printf("-a : Combat strength and hit points for unit" " 'A'\n"); printf(" Both values must be given if -a is specified" "\n"); printf("-b : Combat strength and hit points for unit" " 'B'\n"); printf("\nThe retreat probability for a fast unit can be specified\n" "in either of two ways\n"); printf("-r : retreat probability for unit a\n"); printf("-e : experience level\n"); printf(" 0 - no retreat\n"); printf(" 1 - conscript\n"); printf(" 2 - standard\n"); printf(" 3 - veteran\n"); printf(" 4 - elite\n\n"); printf("(Or you can alter values in the program and recompile)\n\n"); exit(0); } else { fprintf(stderr, "Unrecognised option '%s'\n", argv[i]); exit(-1); } } a = a_st / (a_st + b_st); /* probability that A wins 1 round */ b = 1.0 - a; /* probability that B wins 1 round */ s = 1.0 - r; /* probability of not retreating */ /* wins where retreat isn't important */ for (i = 0; i <= (hp_a - 2); i++) { coeff = fac(hp_b + i - 1) / (fac(hp_b - 1) * fac(i)); prob = coeff * pow(a, hp_b) * pow(b, i); array[hp_a - i][0] += prob; p_win += prob; } /* wins where no retreat because B is on 1 hp */ coeff = fac(hp_b + hp_a - 3) / (fac(hp_b - 1) * fac(hp_a - 2)); prob = coeff * pow(a, hp_b) * pow(b, hp_a - 1); array[1][0] += prob; p_win += prob; /* wins where attempt to retreat fails */ for (i = 0; i <= (hp_b - 2); i++) { coeff = fac(hp_a + i - 2) / (fac(hp_a - 2) * fac(i)); prob = coeff * pow(a, hp_b) * pow(b, hp_a - 1) * s; array[1][0] += prob; p_win += prob; } /* succesful retreats */ for (i = 0; i <= (hp_b - 2); i++) { coeff = fac(hp_a + i - 2) / (fac(hp_a - 2) * fac(i)); prob = coeff * pow(a, i) * pow(b, hp_a - 1) * r; array[1][hp_b - i] += prob; p_retreat += prob; } /* losses where no retreat because B is on 1 hp */ coeff = fac(hp_b + hp_a - 3) / (fac(hp_b - 1) * fac(hp_a - 2)); prob = coeff * pow(a, hp_b - 1) * pow(b, hp_a); array[0][1] += prob; p_lose += prob; /* losses where retreat fails */ for (i = 0; i <= (hp_b - 2); i++) { for (j = 0; j <= (hp_b - i - 1); j++) { coeff = fac(hp_a + i - 2) / (fac(hp_a - 2) * fac(i)); prob = coeff * pow(a, i + j) * pow(b, hp_a) * s; array[0][hp_b - i -j] += prob; p_lose += prob; } } printf("\nA:\n hp: %d combat strenth: %.2f\n", hp_a, a_st); if (r != 0) printf(" retreat chance: %.2f\n", r); printf("B:\n hp: %d combat strenth: %.2f\n\n", hp_b, b_st); printf("Hit points remaining:\nA \\ B"); for (i = 0; i <= hp_b; i++) printf("%3d ", i); printf("\n"); for (j = 0; j <= hp_a; j++) { printf("%3d ", j); for (i = 0; i <= hp_b; i++) { if (array[j][i] != 0.0) printf("%4.1f ", array[j][i] * 100.0); else printf(" - "); } printf("\n"); } printf("\nA wins:\t\t%4.1f %%\n", p_win * 100.0); if (p_retreat != 0.0) printf("A retreats:\t%4.1f %%\n", p_retreat * 100.0); printf("B wins:\t\t%4.1f %%\n\n", p_lose * 100.0); return(0); } double fac(int x) { if (x == 0) return(1.0); else return(x * fac(x - 1)); }