Chance / Percentage Script

wdym by not accurate? also which one will work

1 Like

You should seed math.random() before using to allow more randomness in the generation of the numbers, i.e. math.randomseed(os.clock()). If you are using it for player chance percentage then a better method is to use:

local rand = Random.new(os.clock());
local new_number = Random:NextNumber();

Since this has a single pool to draw numbers from and no other scripts can pull the next value from it (unless you allow it to). Whereas math.random() will be shared by any player that pulls from it so could skew players actual chances. I use the pseudo-random (between 0 and 1) number returned from Random.NextNumber() as a decimal percentage and multiply this by the required range. We have to use math.round() + 0.5 to remove the 0 from the range since 0-100 contains an extra interval between 0 and 1 so there are actually 101 intervals.

The code below is a method for getting a fair(ish) chance of getting 1-in-million chance. Increase the luck_bonus to change the chances to (1*luck_bonus) in-million, so to get 8 in a million set it to 8. By the law of averages most players should win the odds but it doesn’t always happen. iteration represents each player and i the number of times they had to try. You can adapt this code to include a table of ranges for different odds.

local iteration = 0;
local chance = 1000000;
local luck_bonus = 1;
local rand = Random.new(os.clock());

while true do
	
	iteration += 1;
	local success = false;
	for i=1, chance do
		local new_number = math.round((rand:NextNumber() * chance) + 0.5);
		if new_number <= (1 * luck_bonus) then
			warn("Player",iteration,"success after",i,"attempts with",new_number);
			success = true;
			break;
		end
	end
	
	if success == false then
		print("Player",iteration,"failed",chance,"attempts");
	end
	
	wait(1);
	
end
2 Likes

While I acknowledge that my first solution may provide unexpected results due to tables being read as un-ordered, I’m not sure what you mean by saying my script won’t work or would be inaccurate?

Can you clarrify your reasoning for the benefit of this topic and myself in case I’ve missed something?

1 Like

what about this?

1 Like

It’s a good example with the table provided. It does choose things with a good spread of randomness (again Random:NextInteger() would provide a single pool which wont skew the players chances). I wouldn’t recommend using this method for any percentages that go beyond values between 1 and 100 or 1 and 1000. Any chance table that is 1/10000 or 1/1000000 will generate a huge table during initialisation.

print("Perk Chance script v.1.0")

-- Table for all the chances for each perk.
local Chances = {
	SpeedBoost = 60,
	JumpBoost = 32,
	Regen = 7,
	LowGravity= 1,
	Death = 50
}

local TimesPicked = {}

-- Value for the choosen chance.
local ChoosenChance = math.random(0, 100) -- Chooses a random number from 0 to 100.

-- For loop to loop through all the chances.
for k,v in pairs(Chances) do
	if ChoosenChance <= v then -- If the choosen chance is less or equal to the chance.
		print(k) -- Print the perk.
		break
	end
end

--[[
	This loop is for testing the chances, this means it is not needed for the actual game.
	We will keep this loop in for now.
]]
for i = 1, 1000, 1 do
	local ChoosenChance = math.random(0, 100)
	for k,v in pairs(Chances) do
		if ChoosenChance <= v then
			TimesPicked[k] = (TimesPicked[k] or 0) + 1
		end
	end
end

print(TimesPicked)

Good example again but having zero in the range, i.e.

local ChoosenChance = math.random(0, 100);

Means that they have 2 chances to get LowGravity (i.e. 0 and 1), it should be:

local ChoosenChance = math.random(1, 100);

And like I have said several times in this post. math.random() uses a single pool. That means other scripts can access the pool, i.e. random effects you have running, random movement, etc… This means the pool is unfair. Some player can join and get the lowest percent on the first draw, when someone was just about to draw their 99th number. Use Random.new(os.clock()):NextInteger(1,100) for a fair number sequence that only one script can access.

perks = {
	{name = "Health", chance = 5},
	{name = "Ammo", chance = 5},
	{name = "Speed", chance = 5}
}

function getRandomPerk()
	local totalChance = 0

	for i, perk in ipairs(perks) do
		totalChance = totalChance + perk.chance
	end

	-- Pick a random number between 1 and totalChance
	local randomNumber = math.random(1, totalChance)
	local cumulativeChance = 0

	-- Loop through the perks and compare the random number with the cumulative values
	for i, perk in ipairs(perks) do
		cumulativeChance = cumulativeChance + perk.chance

		if randomNumber <= cumulativeChance then
			-- If the random number is less than or equal to the cumulative chance
			-- return the current perk
			return perk
		end
	end
end

print(getRandomPerk())
1 Like

your script is good and everything but, the items have exactly equal chances, you are using math.Random which will return any of the numbers except ones with decimals so getting a 1.5 is basically impossible so I dont think its reliable, Here is what I normally use

function ChooseItem(Table)
	local TotalWeight = 0
	for i,v in pairs(Table) do
		TotalWeight = TotalWeight + v.Rarity
	end
	local Chance = math.random(1,TotalWeight)
	local Counter = 0
	for i,v in pairs(Pets) do
		Counter = Counter+v.Rarity
		if Counter >= Chance then
						
			return v.Name
		end
	end
end

and to get an item just do

local Items = {
	Item1 = {
		Name = "anything1";
		Rarity = 10
	};
	Item2 = {
		Name = "anything2";
		Rarity = 20
	};
	Item3 = {
		Name = "anything3";
		Rarity = 30
	};
	Item4 = {
		Name = "anything4";
		Rarity = 40
	};
}
local ItemChosen = ChooseItem(Items)
print(ItemChoosen)

Can you please revise ur script I don’t quite understand also are the rarities from top to bottom low to high?

it doesn’t matter, you can place them randomly