Hello, I have a module script with a bunch of different rarities and what their percent of being chosen is. I know I need to make a weighted chance system and I’ve tried looking for an example but haven’t really found anything. Basically what I want to achieve is a function that randomly selects a rarity from the module script and each rarity has a different chance of being chosen. Ex: If rare had a weight of 20 it would have a 20% chance of being chosen or if legendary had a 0.1 weight it would have a 0.1% chance.
Module script:
local Rarities = {
['Basic'] ={
weight = 30,
multi = 1,
};
['Common'] ={
weight = 10,
multi = 1,
};
['Uncommon'] ={
weight = 5,
multi = 1,
};
['Rare'] ={
weight = 1,
multi = 1,
};
['Legendary'] ={
weight = 0.66,
multi = 1,
};
}
return Rarities
a good way to do this is to use a table like this:
local rarities = require(MODULESCRIPT)
local function ChooseWeighted()
local weightTable = {}
for t, weight in pairs(rarities) do
local multiplier = weight.weight * 100
for m = 1, multiplier do
weightTable[m] = t
end
end
local selection = weightTable[math.random(1, #weightTable)]
return selection
end
There’s a more performance and memory friendly way to do it that allows any precision (ie you can have a chance of any arbitrarity number, like 1342.352189 if you really wanted to).
In your case it would look like:
local Rarities = {
['Basic'] ={
weight = 30,
multi = 1,
};
['Common'] ={
weight = 10,
multi = 1,
};
['Uncommon'] ={
weight = 5,
multi = 1,
};
['Rare'] ={
weight = 1,
multi = 1,
};
['Legendary'] ={
weight = 0.66,
multi = 1,
};
}
local random = Random.new()
local function generateRarity()
local totalWeight = 0
-- get the total weight
for _, rarity in Rarities do
totalWeight += rarity.weight * rarity.multi
end
-- choose a weight
local chosenRarity = random:NextNumber(0, totalWeight)
-- find a rarity that matches said weight
for rarityName, rarity in Rarities do
local calculated = rarity.weight * rarity.multi
if chosenRarity <= calculated then
return rarityName
end
chosenRarity -= calculated
end
end
--[[ total weight = 46.66, so with 1 million iterations we can predict that we will get about:
Basic: 642948.993 (30 / 46.66 = 0.642948993 @ 1,000,000 iterations gives us roughly 642948.993)
Common: 214316.331
Uncommon: 107158.165
Rare: 21431.633
Legendary: 14144.877
]]
local generated = {}
for i = 1, 1_000_000 do
local r = generateRarity()
generated[r] = generated[r] or 0
generated[r] += 1
end
print('Basic:', generated.Basic)
print('Common:', generated.Common)
print('Uncommon:', generated.Uncommon)
print('Rare:', generated.Rare)
print('Legendary:', generated.Legendary)