Mathy question - related to balancing random number generation

Alright, so here’s my problem.

I have a list of stats, and I want divide an “upgrade” between them all randomly.

My problem is that certain stats can’t be anything other than integers - and this makes them limited to being increased by 1. Hence, this causes a “weighting” effect, where because they always get +1, and other stats can get anywhere from 0-1, the integer-only stats tend to have much higher values.

My question is, how would I counteract this weighting effect? Is there a certain type of math I could do to figure out what the likelyhood should be of increasing an integer value relative to the rest?

My current code is something like

upgradeAmount = 34.7 

statList = {
attack = 10,
range = 10,
magSize = 10 -- Integer only

while upgradeAmount > 0 do

stat = statList[math.random(1,#statList)]

if not integerOnly then
up = math.min(math.random(),upgradeAmount)
up = 1
if up > upgradeAmount then continue end

stat = stat + up
upgradeAmount = upgradeAmount - up


You could just assume all are non-ints and round the ints at the end:

while upgradeAmount > 0 do
	local up = math.min(math.random(), upgradeAmount)
	statList[math.random(1, #statList)] += up
	upgradeAmount -= up

for i = 1, #statList do
	if integerOnly(i) then
		statList[i] = math.floor(statList[i]) -- or math.floor(statList[i]+0.5) for rounding
1 Like

I could do that - the problem there is that I would lose out on distributing the full “UpgradeAmount”.

But, seeing that, perhaps it might be worth it to just subtract the extra from the Integers, and then do another “upgrade loop” with the remainder on the rest of the non ints.

Thank you for the response ^.^

That’s just changing the probabilities in the other direction :slight_smile:

The only way to do it without changing the probabilities or underusing the upgrade amount would be to store all the stats as non-ints.

Then if you need to get a stat (to display on a GUI, for instance, or calculate ammo left), just round it before you use it.

That way your magSize might internally be 24.6, but when you calculate the amount of ammo remaining you do math.floor(magSize) - ammoUsed.

Then in the future if your magSize only gets 0.5 of the upgradeAmount, it’ll pop over the threshold to 25.1 (which now you would use as 25).

You could wrap this all in an object with some metatable nonsense (or getter methods) to hide all the rounding and ensure you never forget.


Yes, you’re right. - perhaps changing the probabilities is still my best bet, but it might also work better than the alternative.

The problem with distributing the stats that way is that effectively, the extra .6 on the 24.6 round mag would be useless. In the end, the player would be losing out on .6 of a potential upgrade for another stat, and I still run into the underusing problem.

Might not seem like a big deal with the example I gave - but in the actual use case, the stats range from 0-1, and work based off of a percentage. So .6 of a mag could work out to be a 10% or more loss in certain cases. Plus, this is for the most part a one-time generation in my game, so it isn’t like the .6 could be added onto in the future to make up for it.

If the math for the probability isn’t something you could help with, or don’t want to help with,
do you or anyone else know of a good place to get the info to figure out problems like this?

Wait, so how are they integers?

In that case then yes, your solution of redistributing the extra from the ints seems OK. I was imaging this as a like per-level upgrade or something, where the fractional part of the integer stats would accumulate over time.

Not sure. It’s less of a probability problem and more of a “what tradeoff do you want to make” problem.

1 Like

I apply the percentage to a minimum-maximum range of a stat. I add up to 10% per “stat selection”, but with the stats that are integers I just did the math to add whatever percentage is “1”, at a time.

That does make sense actually, I really appreciate the clarity with how everything was worded and explained, thank you!