How I can get 1 random spawner from this dictionary, if the higher Spawner Volume, the more chance it should have to become selected?
[Example: Spawner2 should have the highest chance to be seleted, but Spawner3 - the least]
local list = {}
local chances = {
Spawner1 = 25,
Spawner2 = 50,
Spawner3 = 10,
}
for thing, percentage in pairs(chances) do
for i = 1, percentage do
table.insert(list, thing)
end
end
-----
local choice = list[math.random(#list)]
you can simply try this by putting for example 100 On a spawner
That’s good, but 25, 50 and 10 was only for example. Actual Spawners Volume is around 1000000, and inserting 1000000 times 100 spawners isn’t best idea…
local sum = 0
local chances = {
Spawner1 = 25,
Spawner2 = 50,
Spawner3 = 10,
}
for thing, chance in pairs(chances) do
sum = sum + chance
end
local index = math.random() * sum
local choice
for thing, chance in pairs(chances) do
index = index - chance
if index <= 0 then
choice = thing
break
end
end
print(choice)
I tryed this variant before posting here - idk why, but pairs() almost 80% times gives the same combination of selected spawners (Ex: Sp2-Sp3-Sp1, Sp2-Sp3-Sp1, Sp2-Sp1-Sp3, Sp2-Sp3-Sp1, Sp2-Sp3-Sp1), and due to this even the smallest spawner can have the most trees.
It can always be a coincidence, there are an infinite number of cases, You will never know if it is really correct, I am sure of my scripts because putting 100 always comes out that.
You question is not right, you don’t want to randomize a dictionary but instead you want to do weighted randomness with a dictionary containing weights of every key.
Here is my solution to your problem:
local function weighted_random(weights)
local sum = 0
for k, v in pairs(weights) do
sum = sum + v
end
local rnd = math.random(0, sum)
for k, v in pairs(weights) do
if rnd < v then
return k
end
rnd = rnd - v
end
error("Something went wrong!")
end
local Spawners = {
Spawner1 = 25,
Spawner2 = 50,
Spawner3 = 10,
}
print(weighted_random(Spawners))
Also for people who knows that the sum of all the weights gonna be 100 for example:
local function weighted_random(weights)
local rnd = math.random(0, 100)
for k, v in pairs(weights) do
if rnd < v then
return k
end
rnd = rnd - v
end
assert("Something went wrong!")
end
local spawners = {
Spawner1 = 10,
Spawner2 = 80,
Spawner3 = 10,
}
print(weighted_random(spawners))
That’s just a safe guard. that basically means the code should never reach that point or something went wrong somehow unexpected, but if the function is used properly, everything should be fine.
If somehow the function failed because of wrong data or usage somehow then it will error.
I maked system like your. Now, it picks only 1 spawner all time, and spawns trees only on it.
local TotalWeight = 0
for Spawner, Weight in pairs(SpawnerObjects) do
print(Spawner)
print(Weight)
TotalWeight = TotalWeight + Weight
end
local RandNum = math.random(0, TotalWeight)
for Spawner, Weight in pairs(SpawnerObjects) do
if RandNum <= Weight then
SelectedSpawner = Spawner
else
RandNum = RandNum - Weight
end
end
I FIND PROBLEM. After receiving RandomNum <= Weight, it was able to go lower than 0 (-214421.908241). After adding “break” it works like needed! Everyone thanks for help!