How to make a chance system with very rare chances

For a very very very long time now I have been trying to make an accurate chance system like Bubble gum sim (https://www.roblox.com/games/2512643572/UPDATE-67-Bubble-Gum-Simulator?refPageId=5dea1f34-0d0d-4b49-a6a1-acbd0e5a9b2c) with % out of 100% and just can not figure out how.

Basically. Lets say I have:
Doggy: 40%
Kitty: 30%
Bunny: 15%
Bear: 10%
Dragon: 3.07%
Demon: 1%
Angel: 0.02%
Snowball: 0.01%

how would i make the most accurate chance system i can possibly get out of those.

I have searched everywhere and tried tons of methods myself but the chances just dont seem accurate what so ever, people getting 1/5 millions in like 5k eggs constantly

2 Likes

I believe the normal method is checking if a random number is above/below a certain range - and I believe thats the most accurate method

so in this case i have to check a number 0.01 - 100%

I believe so (it is late at night and I was boredly searching devforum - excuse me for any typos)
i.e

local chance = math.random(0,1000)
if chance == 1 then -- 1 / 1000th Chance
   -- Do stuff
end
3 Likes

so thats how i would get the lowest chance one, lets say for the 3.07%, would i just multiply the 3.07 by a certain amount and check if chance == the 3.07 multiplied

I suggest checking out this DevForum post regarding weighted randoms: Weighted Selection

3 Likes

I believe for 3.07 itd be chance =< 307, instead of chance == 1

well ive tried weighted selections before, would this work with decimals? that is pretty much my biggest concern

yes but if table was 0.1 would that even work, i think math.random() only works with whole numbers (sorry if im wrong its late and im tired)

You can always just “fake” the decimal chances by making the numbers larger.

ex: Item 1 has .10% chance, item 2 has 99.90% chance:

item 1 weight: 1
item 2 weight: 999

so if i multiplied 0.01 by 10 until it became a whole number, i do that to all the numbers and use math.random() from there

I just tested and decimals would not work in this situation. However, you can multiply the percentage by 100 to get an accurate weight.

ah so as i said in my last reply to outcharm, i just multiply until its a whole number, thatll be accurate?

Not necessarily because if it is already a whole number, the weighing would be unbalanced because all of a sudden all the numbers a whole. You should use a common multiplier on all the numbers to keep the proportionality.

Modified Code:

function percentToWeight(percent)
	return percent * 100 --Change this if needed, I assumed 100 because you are only going to the 100ths place
end

local Items = {
	{"Table", percentToWeight(0.01)},
	{"Lamp", percentToWeight(0.5)},
	{"Chair", percentToWeight(0.25)},
}
local TotalWeight = 0

for _,ItemData in pairs(Items) do
	TotalWeight = TotalWeight + ItemData[2]
end

local function chooseRandomItem()
	local Chance = math.random(1,TotalWeight)
	local Counter = 0
	for _,ItemData in pairs(Items) do
		Counter = Counter + ItemData[2]
		if Chance <= Counter then
			return ItemData[1]
		end
	end
end

for i = 1, 20 do
	print(chooseRandomItem())
end

You just have to multiply it by the right number yes, like in the example I provided, I just multiplied everything by 10 so they were all whole numbers:

.1 -> 1, 99.9 -> 999

If you want to use smaller decimals, such as .01, you’d need to multiply them by 100, and for .001 by 1000 and so on.

well the 0.01 was just an example, the core of the game has to do with rng so itd be up to the millions or however id like the rarest to be

also, there will be a lot of changes from the rarest in the egg, so how would i be able to make it check how much is necessary

You can use functions to calculate total weights so you can have very rare chances, such as .001% and very common chances, such as 5%.

See here (you’d need to modify this code to work for yourself obviously):


local eggs = {}

eggs.Egg1 = {
	Dog = 45; -- 45 % chance
	Cat = 45; -- 45 % chance
	Dinosaur = 10; -- 10% chance
}

eggs.Egg2 = {
	Cow = 99999; -- 99.999% chance
	Rainbow_Cow = 1; -- 0.001% chance
}


function GetChanceOfEgg(egg)
	local chance = 0
	
	for eggName,eggChance in pairs(egg) do
		chance += eggChance
	end
	
	return chance
end


function PickRandomFromEgg(egg)
	
	local chance = GetChanceOfEgg(egg)
	
	local chance = math.random(0, chance)
	
	for eggName,eggChance in pairs(egg) do
		chance -= eggChance
		
		if chance <= 0 then
			return eggName
		end
	end	
end



local pet = PickRandomFromEgg(eggs.Egg2)


print(pet)


-- Extra Code To Test Probability:

local n = 0

repeat chosenPet = PickRandomFromEgg(eggs.Egg2) n += 1 until
chosenPet == "Rainbow_Cow"

print("It took " .. n .. " tries until you got a " .. chosenPet)

local Items = {
	{"Table", 2},
	{"Lamp", 0.5},
	{"Chair", 0.25},
}

local multiplier = 1

for _, item in pairs(Items) do --Essentially edits the multiplier so that even the smallest decimal will become whole
	local function zeros(amount)
		local total = "1"
		for i = 1, amount do
			total = total.. "0"
		end
		return total
	end
	local split = string.split(tostring(item[2]), ".")
	if split[2] ~= nil then
		if tonumber(zeros(string.len(split[2]))) > multiplier then
			multiplier = tonumber(zeros(string.len(split[2])))
		end
	end
end
print(multiplier)
for _, item in pairs(Items) do
	item[2] = item[2] * multiplier
end

local TotalWeight = 0

for _,ItemData in pairs(Items) do
	TotalWeight = TotalWeight + ItemData[2]
end

local function chooseRandomItem()
	local Chance = math.random(1,TotalWeight)
	local Counter = 0
	for _,ItemData in pairs(Items) do
		Counter = Counter + ItemData[2]
		if Chance <= Counter then
			return ItemData[1]
		end
	end
end

for i = 1, 20 do
	print(chooseRandomItem())
end
14 Likes

well ive tested this with lamp and table, table being 0.01% and i got it at a reasonable attempt so its all looking good so far, thanks

3 Likes

Glad @outcharm and I could help :smile:! Reply if you come across anything else relating to the code that was sent.

4 Likes