Skip to content

How to calculate the chance of applying a bonus(i.e crit chance)?

An answer to this question on Stack Overflow.

Question

Sorry if the question isn't clear, english is not my main language so i didn't knew how to compose it. My teacher gave an exercise to calculate who would win in a duel giving their health and attack. I wanted to expand on it a bit and added armor, critical chance and critical damage as extra stats, now I'm trying to figure out how to apply the chance of a critical in the damage. Here is where I've got so far.

#include <stdio.h>
#include <stdlib.h>
typedef struct {
    int HP;
    int damage;
    int armor;
    float crit_damage;
    float crit_chance;
} atributes;
//how to implement crit_chance?
//using a function?
//divide 100 for the crit_chance
//Ex: crit_chance = 25 ; 100/25 = 4
//generate a random number between 1 and 4
//if the number is 4 the crit_chance is sucessfull
//if not then the crit_chance fails
//aply then the result of the funcion to character[i].crit_damage
int main() {
    int i, rounds = 0;
    atributes character[2];
    for(i = 0; i < 2; i++) {
	    printf("\tCharacter %d atributes\n", i+1);
	    printf("	Damage = ");
	    scanf("%d", &character[i].HP);
	    printf("	HP = ");
	    scanf("%d", &character[i].damage);
	    printf("	Armor = ");
	    scanf("%d", &character[i].armor);
	    printf("	Crit Damage = ");
	    scanf("%f", &character[i].crit_damage);
	    printf("	Crit Chance = ");
	    scanf("%f", &character[i].crit_chance);
	    printf("\n");
    }
    while ((character[0].HP > 0) || (character[1].HP > 0)) {
	    character[0].HP -= (character[1].damage * (character[1].crit_damage) - character[0].armor * 2);
	    character[1].HP -= (character[0].damage * (character[0].crit_damage) - character[1].armor * 2);
	    rounds++;
    };
    if (character[0].HP > character[1].HP) printf("\tCharacter 1 won after %d rounds!", rounds);
	    else if (character[0].HP < character[1].HP) printf("\tCharacter 2 won after %d rounds!", rounds);
		    else printf("\tThe duel ended in a tie after %d rounds", rounds);
    return 0;
}

Answer

Something like the following works:

int is_critical = (rand()%4==3);

rand() is a function provided by stdlib.h which returns a value inclusively between 0 and RAND_MAX (a constant defined in stdlib.h).

rand()%4 gives you the remainder when this value is divided by 4: this will be a number 0, 1, 2, or 3.

Asking rand()%4==3 asks if the result is equal to 3 (though you could just as well choose 0, 1, or 2). Since 3 represents 25% of the outcomes, this corresponds to what you want and is_critical is 1 if there's a hit.

A caveat, though, since RAND_MAX is probably not evenly divisible by 4 some of the modulus results have a slightly higher chance of occurring than others, so you would never want to generate random numbers this way for anything that really matters (science, finance, crypto, &c).

You can generalize this method as follows:

int is_critical = (rand()/(float)RAND_MAX)>0.75;

Since both rand() and RAND_MAX give integers and RAND_MAX is larger than rand(), dividing them gives 0. So we convert RAND_MAX to float. The result is a "uniformly" distributed number in the range 0-1. This is greater than 0.75 with 25% chance, which is what you want.