I\'m a web-game developer and I got a problem with random numbers. Let\'s say that a player has 20% chance to get a critical hit with his sword. That means, 1 out of 5 hits
I see a lot of answers suggesting to keep track of the previously generated numbers or to shuffle the all possible values.
Personally, I do not agree, that 3 crits in a row is bad. Nor I agree that 15 non-crits in a row is bad.
I would solve the problem, by modifying the crit chance it self, after each number. Example (to demonstrate the idea):
int base_chance = 20;
int current_chance = base_chance;
int hit = generate_random_number(0, 100) + 1; // anything from 1 to 100
if(hit < current_chance)//Or whatever method you use to check
{
//crit!
if(current_chance > base_chance)
current_chance = base_chance; // reset the chance.
else
current_chance *= 0.8; // decrease the crit chance for the NEXT hit.
}
else
{
//no crit.
if(current_chance < base_chance)
current_chance = base_chance; // reset the chance.
else
current_chance *= 1.1; // increase the crit chance for the NEXT hit.
//raise the current_chance
}
The longer you don't get a crit - the higher chance you have for your next action to crit. The reset I included is entirely optional and it would need testing to tell if it's needed or not. It may or may not be desirable to give a higher probability of a crit for more than one action in a row, after a long non-crit action chain.
Just throwing in my 2 cents...
You've got a misunderstanding of what random means.
Which of these is more random?
While the second plot looks more evenly distributed, the more random is actually the first plot. The human mind often sees patterns in randomness, so we see the clumps in the first plot as patterns, but they're not - they're just part of a randomly selected sample.
Reaction on: "The problem is I got very bad real life results -- sometimes players get 3 crits in 5 hits, sometimes none in 15 hits."
You have a chance of somewhere between 3 and 4 % of getting nothing in 15 hits...
What you want are not random numbers, but numbers which seem random to a human. Other have already suggested individual algorithms, which can help you, like Shuffle Bad.
For a good detailed and extensive analysis of this domain see AI Game Programming Wisdom 2. The whole book is worth reading for any game developer, the idea of "seemingly random numbers" is handled in chapter:
Filtered Randomness for AI Decisions and Game Logic:
Abstract: Conventional wisdom suggests that the better the random number generator, the more unpredictable your game will be. However, according to psychology studies, true randomness over the short term often looks decidedly unrandom to humans. This article shows how to make random AI decisions and game logic look more random to players, while still maintaining strong statistical randomness.
You may also find another chapter interesting:
The Statistics of Random Numbers
Abstract: Random numbers are used most heavily by Artificial Intelligence and games in general. To ignore their potential is to make the game predictable and boring. Using them incorrectly can be just as bad as ignoring them outright. Understanding how random numbers are generated, their limitations and their capabilities, can remove many difficulties of using them in your game. This article offers insight into random numbers, their generation, and methods to separate good ones from bad.
You are looking at a linear distribution, when you probably want a normal distribution.
If you remember back in your youth playing D&D, you were asked to roll multiple n-sided die, then sum the results.
For instance, rolling 4 x 6-sided die is different than rolling 1 x 24-sided dice.
City of Heroes actually has a mechanic called the "streakbreaker" that solves exactly this problem. The way it works is that after a string of misses of a length related to the lowest to-hit probability in the string, the next attack is guaranteed to be a hit. For example if you miss an attack with over 90% to hit chance then your next attack will auto hit, but if your hit chance is lower like 60% then you'll need to have several consecutive misses to trigger the "streakbreaker" (I don't know the exact numbers)