Conceptually, generating item stats is the same as placing balls into buckets. An even distribution of 50 balls into 5 buckets looks like this: [10,10,10,10,10] whereas an uneven distribution might look like this: [37,0,12,0,1]. I want a very uneven distribution but not so uneven that 1 bucket has all the balls. Here are some properties that I desire:
- Numbers are very unevenly distributed
- Small numbers (e.g. 0-10, 10-100) appear more often than 0
- Very large numbers (e.g. those exceeding 50% of total balls) appear frequently (e.g. >20% of the time)
One method I've thought of is this: for each ball, roll a die, if the result is below a threshold then add the ball to the previous bucket, otherwise randomly choose a new bucket. Python code as follows:
from random import randint
stats = [0] * 25
threshold = 9985
cur_bucket = randint(0,len(stats)-1)
for i in range(10000):
c = randint(0,9999)
if c > threshold:
cur_bucket = randint(0,len(stats)-1)
else:
stats[cur_bucket] += 1
print(stats)
Example result: [0, 1693, 0, 0, 0, 0, 231, 0, 122, 0, 258, 0, 0, 1422, 0, 0, 2406, 526, 0, 0, 2759, 148, 0, 419, 0]
As you can see there are a lot of 0s and no numbers between 0 and 100, but quite a few numbers in the 1000-3000 range.
Another way is to choose a bucket for each ball where the probability of choosing a bucket is proportional to the number of balls already in the bucket. Python code as follows:
from random import randint
stats = [1]*25
cumsums = stats[:]
def recalc():
global cumsums
global tot
tot = 0
for i,v in enumerate(stats):
tot += v
cumsums[i] = tot
for i in range(10000):
recalc()
n = randint(0,tot)
for j in range(len(cumsums)):
if cumsums[j] > n:
stats[j] += 1
break
print(stats)
Example result: [766, 426, 241, 517, 345, 491, 350, 495, 1073, 8, 127, 740, 2, 91, 883, 208, 1041, 208, 49, 287, 22, 50, 16, 269, 1316]
This method (suggested by a friend) generates a much nicer distribution, notice how there are both small numbers (1, 2, 3, etc) as well as large. You can see all numbers from 0-10, 10-100, 100-1000 and higher up.
But with this method it's also very rare to see numbers above 3000 (I only saw it once in over 30 runs of this program so it does happen but doesn't appear often). Whereas with my previous method, it was quite common to see numbers above 4000.
What other methods are there for generating uneven distributions of numbers for items? Or, how can my existing methods be improved?