Weighted Randomness

I have a central idea on how to code this but every attempt I’ve tried its came out either the weights not correlating correctly or it just being finicky.

Basically what I’m going for is a function where it cycles through a list of objects, every object having a rarity
ex) {Name = Iron; Rarity = 2}

It would then run math.random(1,2) say if it chose 1 then cycle to the next one until it doesn’t roll 1 and then choose that one as the chosen object. I dont know how/ what more to explain so yeah.

Lost the code since I was experimenting in the same script and didn’t save it so I’m just starting fresh and right.

1 Like

This is not weighted randomness since you are not selecting items based on their weight, it’s literally 50-50. You want to iterate through their weights in lieu with a counter and set up the weights such that they add up to a nice number like 100

local rarities = {
   [“Iron”] = 70;
   [“Bronze”] = 25;
   [“Gold”] = 5
}
local counter = 0
local num = math.random(1,100)
for item,rarity in pairs(rarities) do
   counter += rarity
   if counter >= num then
      print(item..” selected!”)
      break
   end
end

Maybe try something like this:

local rarities = {
	{ item = "Iron", weight = 70 },
	{ item = "Bronze", weight = 25 },
	{ item = "Gold", weight = 10 },
}

local ironNum = 0
local goldNum = 0
local bronzeNum = 0

local function getWeightedRandom(lootTable)
	local totalWeight = 0
	for _, entry in ipairs(lootTable) do
		totalWeight = totalWeight + entry.weight
	end

	local randomWeight = math.random() * totalWeight
	local cumulativeWeight = 0

	for _, entry in ipairs(lootTable) do
		cumulativeWeight = cumulativeWeight + entry.weight
		if randomWeight <= cumulativeWeight then
			return entry.item
		end
	end
end

for i = 1, 250 do
	local reward = getWeightedRandom(rarities)
	if reward == "Bronze" then
		bronzeNum = bronzeNum + 1
	elseif reward == "Iron" then
		ironNum = ironNum + 1
	elseif reward == "Gold" then
		goldNum = goldNum + 1
	end
end

print("Iron:", ironNum, "Bronze:", bronzeNum, "Gold:", goldNum)

Added an example at the bottom

This may help you.