return {
Weight = 0,
Chances = { --Chances ranging from 1 to 20 : 20 being highest and 1 being lowest
["Prize1"] = 2, --2 out of 20 being a 10% chance
["Prize2"] = 1, --1 out of 20 being a 5% chance
["Prize3"] = 20, --20 out of 20 being a 100% chance
},
}
Server:
math.randomseed(os.time())
Variables.Weight=0
for _, odds in Variables.Chances do
Variables.Weight += odds
if Variables.Weight >= math.random(1, Variables.Weight) then
print(_) --This always prints because Variables.Weight is always larger than the random value - I don't know what is wrong because I've never done this before and I copied line for line (just changing the references) from several other devforum posts and none of it works.
end
end
The result is that Prize1, Prize2 and Prize3 get printed always meaning, no matter the chance, they will get called up. Why?
Well, math.random(1, Variables.Weight) generates a random integer from 1 to Variables.Weight, inclusive, so the greater than or equal condition will always be true.
There are multiple methods for picking from a weighted table.
If your weights are (and will always be) all integers, you could add a number of copies of the items equal to their weight into an array and pick a random item from the array like this:
local selector = {}
for item, weight in pairs(weightedTable) do
for i = 1, weight do
table.insert(selector, item)
end
end
local random = selector[math.random(1, #selector)]
Alternatively, if you want to use non-integer weights, here’s a function I have:
function SelectRandomKeyFromWeightedTable(tab)
local totalWeight = 0
for item, weight in pairs(tab) do
totalWeight += weight
end
local threshold = Random.new():NextNumber(0, totalWeight)
local current = 0
for item, weight in pairs(tab) do
current += weight
if threshold <= current then
return item
end
end
end
Is the first one based on percentage? I’m trying to convert 20 as an integer to 100% as a percentage and use the chance system to get the likeliest event.
Edit: I tried a few minutes earlier doing
local int = 10
local maximumInt = 20
int/maximumInt*100``` but that doesnt help me in any capacity doesnt work
I’m making a match engine to play out a sport. There are different chances for events which are dynamic and will change according to whats going on in the game.
Foul play, for example, would be a low percentage but would increase if players get angry etc
local chance = 10 -- percentage
local random = math.random(0,100)
if chance > random then
print(random.."%", "You can get the prize")
else
print(random.."%" ,"Next time you will have it")
end
So what this code does is if the chance is 10% and the random was 5% you will get it ether if the chance was 20% you can’t have it
Well, if you’re going to use one of the methods I posted, the effective probabilities would be their weight / total weight.
So prize 1 has a 2 / 23 chance, prize 2 a 1 / 23, and prize 3 a 20 / 23 chance. Is this what you intend? The probabilities you commented in your dictionary don’t make sense, so I’m a little confused.
If you want 20 to be the maximum, you’d have to make all the weights sum to 20. If you want to adjust the probability of one event, you’d have to adjust the probabilities of all the others, so if you want one event to occur 100% of the time for some period, you have to set its weight equal to the max (20) and then change the weights of all other events to 0.
Have you tried using one of the functions I posted?
I tried the first function and it does pick out the most likely event but if its 20, the chance of something happening should be 100% but instead it’s going to the least likely events, at a chance of 1?
And when you want to introduce some other prizes to the pool, you’d have to increase their weights and decrease the weight of prize 3 so that the total weight is still 20.
local Events = {}
for _, i in Variables.Chances do table.insert(Events, _) --[[Add event names to table]] end
math.randomseed(os.time())
local event = Events[math.random(1, #Events)]
print(event)
You’re getting these unexpected results because you’re not using the correct code from the first snippet I posted. You were inserting each event a single time into the array, so all the events effectively had the same chance of occurring. This should be correct.
math.randomseed(os.time())
local events = {}
for event, weight in pairs(Variables.Chances) do
for i = 1, weight do
table.insert(events , event)
end
end
local random = events [math.random(1, #events )]
print(random)
Say your event has a weight of 17. The for i = 1, weight loop would insert 17 copies of the event name into the array.
And if you had another event with a weight of 3, it would insert 3 copies of that event.
Then we pick randomly from the array; there are 17 copies of the first event and 3 copies of the second event, so the first event has a 17 / 20 = 85% chance and second 3 / 20 = 15%.