I have tried several methods but still cannot get the results I want.
Basically, I am transforming different blocks into a variety of materials, some materials need to be commonly spawned and others more rare.
So I have all the blocks in a group, I use a for loop to assign a material to each block, I just haven’t been able to reliably get the rarities to work.
local WeightService = {}
local rand = Random.new()
function WeightService.normalize(weightTable)
local sum = 0
local normalized = {}
for index, weight in ipairs(weightTable) do
sum += weight
end
for index, weight in ipairs(weightTable) do
local newWeight = weight / sum
normalized[index] = newWeight
end
return normalized
end
function WeightService.nextAction(weightTable)
local RandomNumber = rand:NextNumber()
local currentSum = 0
for index, weight in ipairs(weightTable) do
if weight < 0 then
warn("A weight was detected to be negative. The values will be safely normalized again.")
weightTable[index] = 0.01
weightTable = WeightService.normalize(weightTable)
end
currentSum += weight
if RandomNumber < currentSum then
return index
end
end
end
function WeightService.nextActionByBestWeight(weightTable)
local bestIndex = 0
local highestWeight = 0
for index, weight in ipairs(weightTable) do
if weight > highestWeight then
highestWeight = weight
bestIndex = index
end
end
return bestIndex
end
return WeightService
What this does, is you have a weight table with all the weights corresponding to the item in the real array. Then, randomly, a number will be picked. The more probable result will have more range, so the random value from 0 to 1 is more likely to pick it up.
You can use this module if you want to, or you can create something similar. This is just the way I discovered how.