How i can replicate this chance system?

In summary : if i get 239/239 i enable some function, and if it’s not 239 but another random number, call other function

how can i achieve this and manage to do it in percentages?, what would 1/239 equal to in percentage?

3 Likes

You could just do

local r = math.random(1,239)

if r == 239 then
  -- Got lucky
else
 -- Didn't get lucky
end

A 1/239 chance in decimal would literally just be 1 divided by 239, multiply that by 100 to get percent and you have about a 0.4184% chance

1 Like

Thanks for the info, I think this could do it, but since my game needs to rely on accurate random functions, i don’t think math.random would be the best, But thanks anyways, i’ll have that in mind

math.random generates usually perfectly fine random numbers unless you’re doing something that needs to be cryptographically secure.

Although you can use the new Random object which has slightly better results when making multiple random calls very close together.

Besides that, any number your computer generates is going to be puesdo-random in nature without using external sources.

1 Like

Yeah, But Usually weighted systems make use of tables, which kinda concerns me

1 Like

Weighted randomness still uses math.random though, they just make more numbers equal to each different type of thing.

Here’s a post that covers weighted randomness

You just reminded me, i got a weighted system a long time ago, but i forgot what it uses, or what to input

can you help me ?

local Chances = {
    {Rarity = "Blood Hour",     Chance = 50};
    {Rarity = "Vision Hour",    Chance = 30};
    {Rarity = "Blackout",         Chance = 10};
    {Rarity = "Rare+",         Chance = 7};
    {Rarity = "Epic",          Chance = 3};
}

local function GetRandomRarity()
    local Sum = 0

    for , Table in ipairs(Chances) do
        Sum += Table.Chance
    end

    local RNG = Random.new():NextInteger(1, Sum)

    local Weight = 0

    for , Table in ipairs(Chances) do
        Weight += Table.Chance
        if Weight >= RNG then
            return Table.Rarity
        end
    end
end

local RandomRarity = GetRandomRarity()

print(GetRandomRarity())

you see, the chances in the table are 50, 30, 10, 7 and 3, but how i know what porcentage they are?, or what is this system using?

for example, would i put “50” that is 50% or 0.5, that is also 50%?

For the future, this is not a “do it for me” category. You should at least understand the code given to you.

Anyways, weighted systems are essentially just a sum of all values. It doesn’t matter if your values are 50, 30, 10, 7, 3 or 5, 3, 1, 0.7, 0.3, they both have the same odds for the items.

Getting the odds is also basic math: divide your weighted value by the sum all the weighted values (multiplied by 100 for the percentage).

1 Like

Alright, thank you, sorry if i “sounded” too harsh or bad at the beginning, As for that, i said i already got the code, but i was asking for reference or guide in what to change, you can see

I wrote my own WeightedRandom module a few months ago if you would like to use it:

WeightedRandom.lua
--!strict

local WeightedRandom = {}

export type WeightedRandom<I> = typeof(setmetatable({} :: WeightedRandomClass<I>, {} :: WeightedRandomMetatable))

export type WeightedRandomClass<I> = {
	Random: Random,
	GetItems: (self: WeightedRandom<I>) -> {[I]: Item},
	AddItem: (self: WeightedRandom<I>, item: I, weight: number, luckFactor: number?) -> (),
	RemoveItem: (self: WeightedRandom<I>, item: I) -> (),
	GetWeight: (self: WeightedRandom<I>, item: I, luckFactor: number?) -> number?,
	GetWeights: (self: WeightedRandom<I>, luckFactor: number?) -> {[I]: number},
	GetTotalWeight: (self: WeightedRandom<I>, luckFactor: number?) -> number,
	GetProbability: (self: WeightedRandom<I>, item: I, luckFactor: number?) -> number?,
	GetProbabilities: (self: WeightedRandom<I>, luckFactor: number?) -> {[I]: number},
	Next: (self: WeightedRandom<I>, luckFactor: number?) -> I
}

export type WeightedRandomMetatable = {
	__index: (self: any, index: any) -> any,
	__newindex: (self: any, index: any, value: any) -> (),
	__iter: (self: any) -> (),
	__tostring: (self: any) -> string
}

export type Item = {
	Weight: number,
	LuckInfluence: number
}

local function clone<T>(t: T, deep: boolean?): T
	t = table.clone(t :: any) :: any
	
	if deep == true then
		for index: any, value: any in t :: any do
			if typeof(value) == "table" then
				(t :: any)[index] = clone(value, true)
			end
		end
	end
	
	return t
end

function WeightedRandom.new<I>(random: Random?): WeightedRandom<I>
	local items: {[I]: Item} = {}
	
	local weightedRandomClass: WeightedRandomClass<I> = {
		Random = random or Random.new(),
		GetItems = function(weightedRandom: WeightedRandom<I>): {[I]: Item}
			return clone(items, true)
		end,
		AddItem = function(weightedRandom: WeightedRandom<I>, item: I, weight: number, luckInfluence: number?): ()
			items[item] = {
				Weight = weight,
				LuckInfluence = if luckInfluence ~= nil then luckInfluence else 0
			}
		end,
		RemoveItem = function(weightedRandom: WeightedRandom<I>, item: I): ()
			items[item] = nil
		end,
		GetWeight = function(weightedRandom: WeightedRandom<I>, item: I, luckFactor: number?): number?
			if items[item] ~= nil then
				return items[item].Weight + (items[item].Weight * (items[item].LuckInfluence * (if luckFactor ~= nil then luckFactor else 1)))
			else
				return nil
			end
		end,
		GetWeights = function(weightedRandom: WeightedRandom<I>, luckFactor: number?): {[I]: number}
			local weights: {[I]: number} = {}

			for item: I in items do
				weights[item] = weightedRandom:GetWeight(item, luckFactor) :: number
			end

			return weights
		end,
		GetTotalWeight = function(weightedRandom: WeightedRandom<I>, luckFactor: number?): number
			local totalWeight: number = 0

			for _: I, weight: number in weightedRandom:GetWeights(luckFactor) do
				totalWeight += weight
			end

			return totalWeight
		end,
		GetProbability = function(weightedRandom: WeightedRandom<I>, item: I, luckFactor: number?): number?
			if items[item] ~= nil then
				return (weightedRandom:GetWeight(item, luckFactor) :: number) / weightedRandom:GetTotalWeight(luckFactor)
			else
				return nil
			end
		end,
		GetProbabilities = function(weightedRandom: WeightedRandom<I>, luckFactor: number?): {[I]: number}
			local probabilities: {[I]: number} = {}

			for item: I in weightedRandom:GetWeights(luckFactor) do
				probabilities[item] = weightedRandom:GetProbability(item, luckFactor) :: number
			end

			return probabilities
		end,
		Next = function(weightedRandom: WeightedRandom<I>, luckFactor: number?): I
			local weightedItems: {[I]: number} = weightedRandom:GetWeights(luckFactor)
			local totalWeight: number = weightedRandom:GetTotalWeight(luckFactor)
			local randomWeight: number = weightedRandom.Random:NextNumber() * totalWeight
			local lastItem: I = nil

			for item: I, weight: number in weightedItems do
				randomWeight -= weight
				lastItem = item

				if randomWeight <= 0 then
					return item
				end
			end

			return lastItem
		end,
	}
	
	local weightedRandomMetatable: WeightedRandomMetatable = table.freeze({
		__index = function(self: any, index: any): any
			return weightedRandomClass[index]
		end,
		__newindex = function(self: any, index: any, value: any): ()
			if index == "Random" then
				if typeof(value) ~= "Random" then
					error(`invalid value for index '{index}' (Random expected, got {typeof(value)})`, 2)
				end
			else
				error(`{index} cannot be assigned to`, 2)
			end

			weightedRandomClass[index] = value
		end,
		__iter = function(self: any): ()
			error(`attempted to iterate over a WeightedRandom`, 2)
		end,
		__tostring = function(self: any): string
			return `WeightedRandom`
		end
	})
	
	return table.freeze(setmetatable({}, weightedRandomMetatable)) :: any
end

return WeightedRandom

You can use it like so:

-- path to WeightedRandom
local WeightedRandom = require()
-- if you would like to strictly assign types
type WeightedRandom<I> = WeightedRandom.WeightedRandom<I>

-- creates a new WeightedRandom with strictly string items,
-- (or it automatically infers when using WeightedRandom:AddItem())
local myWeightedRandom: WeightedRandom<string> = WeightedRandom.new()

-- setup WeightedRandom
local someTableOdds = {
    ["Common"] = 50,
    ["Uncommon"] = 30,
    ["Rare"] = 10,
    ["Epic"] = 5,
    ["Legendary"] = 3,
    ["Mythical"] = 2
}

for rarity: string, weight: number in pairs(someTableOdds) do
    myWeightedRandom:AddItem(rarity, weight)
    -- optional 3rd parameter for luckInfluence
    -- that defaults to 0
end

-- you can then use the following functions that includes an optional
-- luckFactor argument that defaults to 1
-- (multiplies the odds along with luckInfluence)

-- Get a random item with a luckFactor of 1 (default)
local chosenRarity: string = myWeightedRandom:Next()
print(`Chosen rarity: {chosenRarity}`)

-- Get probabilities with a luckFactor of 5
for rarity: string, probability: number in myWeightedRandom:GetProbabilities(5) do
    print(`{rarity}: {probability * 100}`)
end
1 Like

thank you so much, both of you

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.