Weighted Random

I want to create a function that will return an item from a table where the item has a certain chance of being returned.

I already found some stuff about weighted random functions and tutorials on the DevForum, but none have been very clear on how exactly I can achieve this.

math.random gives all items in a table the same chance of being picked, instead, I want something like this:

local OrderedTable = {
	["This is very common"] = 80, -- 80 percent chance this value is returned
	["This is less common"] = 30, -- 30 percent chance this value is returned
	["This is very uncommon"] = 10 -- 10 percent chance this value is returned
}

What you can do is something like this. Use math.random to get a random number from 1-100. Then have three if statements, one checking if the number is <= 80, another if its > 80 and <= 95, and another if its > 95.

You can adjust the numbers to whatever chance you want but you get the idea. The numbers in your example don’t add up to 100% so I made up some numbers as an example.

2 Likes

It doesn’t have to add up to 100, basically, all common stuff gets a high number, and the less common stuff will get a lower number.

I’m looking for a more efficient way of doing this, I’ll be using this on a table that could get 100+ items, it’s not feasible to spaghetti code 100 if’s and add more code every time I create a new item.

In addition to what @ComplicatedParadigm wrote above,

I actually believe there are existing posts on this topic that might help you:)

1 Like

Just got it working, some DevForum posts about this were a bit unclear, but in my code, there was another factor that made it look like it wasn’t actually working.

I changed this code a bit to get the following function:

function WeightedRandom:RandomFromWeightedTable(OrderedTable)
	local TotalWeight = 0
	
	for Piece, Weight in pairs(OrderedTable) do
		TotalWeight = TotalWeight + Weight
	end
	
	local Chance = math.random(1, TotalWeight)
	local Counter = 0
	for Piece, Weight in pairs(OrderedTable) do
		Counter = Counter + Weight
		if Chance <= Counter then
			return Piece
		end
	end
end

OrderedTable must look like this:

local OrderedTable = {
	["item"] = PickChanceIn%
}
8 Likes