3
\$\begingroup\$

Within Java I have a table of objects ranging from horrible (1%) to wonderful (100%) from which one is randomly selected. This is simple enough and appears on a bell curve with a normal distribution and the average at the 50% mark. But at various stages I wish for this distribution to shift left or right meaning that you are more likely to generate a less pleasant item or at other stages, generate a more pleasant one. The table ranges from 1 to 100.

How do I generate a random number that is biased to one end of the table and not the other, while still being able to, in this case in a bad situation, randomly come up with a 100%? I have looked at Random.nextGaussian(). But this doesn't seem to quite do it, if I am reading it correctly.

\$\endgroup\$
2
  • \$\begingroup\$ I have a few ideas here but you might also consider drawing the distribution you want, and using a nonparametric approach so that you can use arbitrarily shaped distributions. \$\endgroup\$
    – amitp
    Jan 4, 2016 at 17:41
  • \$\begingroup\$ You might try using something like bias or gain to smoothly skew the rolled percentage, via tuning parameters. Check this out: blog.demofox.org/2012/09/24/bias-and-gain-are-your-friend \$\endgroup\$
    – Alan Wolfe
    Jan 5, 2016 at 1:21

3 Answers 3

3
\$\begingroup\$

There's a couple of solutions and I'll touch on them briefly. They can also be combined.

Option 1: Add a flat value

rand(max-min)+min

This produces the entire bell curve shifting left (or right! if supplied a negative min value). While it will exclude items at one and of the range, or the other, this may be beneficial (imagine a scenario where the high/good stuff needs to be common at some point and the maximum increased: during high level play you actually want to exclude the lower value items entirely!)

Option 2: Roll Twice, Pick Better

D&D 5th uses this type of mechanic with regards to advantage/disadvantage: roll twice and pick the higher (advantage) or lower (disadvantage). It has an on-average effect of being the same as adding +5 to a d20 (so about 20% better) but still generates values across the whole continuum (the bell curve gets squished to one side).

Option 3: Inverse Gausian

While this may not be the best solution for you there is in fact an Inverse Gaussian Distribution (or "Wald Distribution") which happens to look like an extremely squished bell curve (smashed up against the lower bound of 0) but the exact curvature can be tweaked to one's desires (but the maximal probability will occur towards the 0-end unless you do a 1-random). I use this one currently in a game I am working on so that things are very consistent with extremely rare deviations, but those deviations, when they occur, are very wild1. Code for how to compute this distribution can be located, though you'll have to piece it together from various sources (it relies on the "error function" which you have to look up independently).

1This means that the player will largely be able to rely on their skills, provided that they are evenly matched +/-1 with the enemies, but still face occasional failures, while as the disparity grows, things become more and more tenuous very rapidly. At +0 the player has a 98% chance of success. At -1, it drops to 92%. At -2, 80%, -3 50%. If the player plays smart they can still survive at a -3 disadvantage (conversely, at a +3 advantage their success rate only rises to only 99.5% or so! So still not a guaranteed success, although it will be very easy).

\$\endgroup\$
0
\$\begingroup\$

You can add another number, from a pre-selected range, to your first number.

Suppose that we're getting 50 on average but want to move that up to 65, you'd add a random number between 0 and (65 - 50) * 2 to your first number.

The formula for shifting the distribution (this is added to each result you generate), therefore is: (target percentage to be the peak - 50) * 2

\$\endgroup\$
0
\$\begingroup\$

Random.nextGaussian() should still work for you if you shift the results. Any real number (to float precision) is technically possible using this method as the constraints are simply that it's 0-centered and has a standard deviation of 1 (ie, a standard normal distribution). All that means is that you just need to shift it (with addition) to wherever you want to position the center and multiply to set the width (standard deviation). All values along the number line are still possible, so you'll also need to restrict it to > 0 and < 101.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .