wdym by not accurate? also which one will work
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
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?
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())
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