Weight (chance system) always being 100%

ModuleScript:

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?

2 Likes

You are doing if 20 >= random(1,20) it will be always bigger because the code sees this
if 20 bigger then or equal to 1-20 then do this end

3 Likes

Yep how do I fix this? The devforum posts I read are doing it that way but they’re getting results and I’m not. Could it be, maybe, because I’m black?

2 Likes

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
1 Like

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
1 Like

Wait, what is this for? Why would there be a prize with a 100% win rate? You’re trying to select randomly from a table given weights, right?

1 Like

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

Maybe this what you want?

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
image
image

i was gonna use math.random() but it has no basis.

math.random(50,100) wouldnt be 50% for example

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.

20 is the maximum chance, being 100%. I need to have an event run at random according to likeliness.

I tried Weighted Chance System but that doesn’t work and I don’t see anyone else complaining so I dunno if its just me

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?

Edit: definitely a step in the right direction.

If the chance of something happening in a group of weights is 100%, then the other events should have a weight of 0. So your table should look like

Chances = { 
		["Prize1"] = 0, 
		["Prize2"] = 0, 
		["Prize3"] = 20, 
	},

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.

Chances = { 
		["Prize1"] = 2, -- 10%
		["Prize2"] = 0, 
		["Prize3"] = 18, -- 90%
	},

Alright I just tried and now the statistically most likely event was only printed twice, which is the lowest out of all in my group.

	Chances = { --Chances ranging from 1 to 20 : 20 being highest and 1 being lowest
		["TurnOver"] = 17, --Most likely
		["Foul"] = 1,
		["ShotSuccess"] = 1,
		["PassSuccess"] = 1,
	},

Yeah I just set all the odds to 0 and put TurnOver to 20 and Foul, ShotSuccess and PassSuccess still got printed.

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)

my code

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)
1 Like

What does the ‘for i= 1’ loop do?

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%.

1 Like