 # Weighted Chance System

Haha! pretty much the same thing, it is a popular system after all.

2 Likes

It was pretty much the only way I could use anything below 1% when for a case opening system, it’s very good lol

1 Like

Yo check this out ``````
local Rarities = { -- ObjectName = frequency (frequency must be an integer)
Item1 = 1,
Item2 = 2,
Item3 = 100,
};

local RollTable = {}

for object_name, frequency in pairs(Rarities) do
for i = 1, frequency do
table.insert(RollTable, object_name)
end
end

local function Roll() --> ObjectName [string]
return RollTable[math.random(1, #RollTable)]
end
``````

Although it may look odd, it’s technically completely good and would be faster to write for non-changing rarity tables.

30 Likes
``````local function roll(t, _a, _b)
return
_a
and (_a > 0
and -math.random(_a)
or _a < 0
and (select(2, next(t, _b)) >= -_a
and next(t, _b)
or roll(t, _a + select(2, next(t, _b)), next(t, _b)))
or (next(t, _b)
and select(2, next(t, _b)) + roll(t, 0, next(t, _b))
or 0))
or roll(t, roll(t, roll(t, 0)))
end

print(roll({Common = 100, Rare = 10, Legendary = 1}))
``````
15 Likes
``````local function roll(t, _a, _b, _c)
return not t and (tonumber(_c) and _c>_b and _a or _c) or (not _c and _a and math.random(_a) or roll(nil, _b, _a, roll(t, _a and _a + _c or 0, next(t, _b))))
end

print(roll{Common = 100, Rare = 10, Legendary = 1})
``````
4 Likes

Nothing better than a module based off of the mechanic people hate most in video games: RNG.

What’s the most preferred method then?

There is no other preferred method, unfortunately.

Don’t worry I have you covered

``````___=next;____=math.random;_____=tonumber;___________=print
-- INLINE CACHINEG??? DOESNT EXIST!!!! OPTIOMIZE!@
function ______(_______,________,_________,__________)return(not(_______)and(_____(__________) and __________>_________ and ________ or __________)or(not(__________)and(________)and(____(________))or(______(nil,_________,________,______(_______,(________)and(________+__________)or(0),___(_______, _________))))))end
___________(______{Common=100,Rare=10,Legendary=1}) -- hhhh
-- AAAAAAAAAAAAA
-- :)
``````
11 Likes

Bro whot is that, I can’t understand a thing…

2 Likes

In full seriousness, unlike my previous reply, there is a better way to do this.

Here is my version of it:

``````local Rarities = {
Common = 0, -- 60% chance
Rare = 0.6, -- 30% chance
Legendary = 0.9, -- 9% chance
Mythic = 0.99, -- 1% chance
}

local function PickRarity()
local Index = math.random()
local HighestRarity = "Common"

for RarityName, Value in pairs(Rarities) do
if Index >= Value and Value >= Rarities[HighestRarity] then
HighestRarity = RarityName
end
end

return HighestRarity
end

for i = 1,100 do
print(PickRarity())
end
``````

When using `math.random`, it will return any number between 0 and 1. The dictionary of rarities stores values that require `math.random` to be greater than or equal to the value in the dictionary. For example, if you want a rare item (from my example), then you would need the random value to be at least 0.6, but less than 0.9 (so that it’s still rare, and not legendary or mythic).

This simplifies rarities and easily allows for adjustments at any time.

@loleris Not sure if you use the initial method you posted long ago, but this may be a better alternative to prevent memory buildup.

10 Likes thanks I just made it a solution as a joke to anyone who understood

``````local function roll(t, _)
return
not _
and roll(t,{0,next(t)})
or _
and table.move({_[#_-2]+_[#_],next(t,_[#_-1])},1,3,#_+1,_)
and #_%3 == 0
and roll(t,_)
or _ == 0
and not table.move({math.random(_[#_])},1,1,1,_)
or table.move({},1,1,#_-#_%3+1,_)
and _[#_] >= _
and _[#_-1]
or table.move({_-_[#_]},1,1,1,_)
and not table.move({},1,3,#_-2,_)
end

print(roll({Common = 100, Rare = 10, Legendary = 1}))
``````
12 Likes

LOLERIS stop my brain hurts what does any of that even mean, like can someone please explain this lol

3 Likes

O(1) solution with O(n) preproc time
from A Lua implementation of the Alias Method, for sampling from an arbitrary distribution. · GitHub

``````local alias_table = {}

function alias_table:new(weights)
local total = 0
for _,v in ipairs(weights) do
assert(v >= 0, "all weights must be non-negative")
total = total + v
end

assert(total > 0, "total weight must be positive")
local normalize = #weights / total
local norm = {}
local small_stack = {}
local big_stack = {}
for i,w in ipairs(weights) do
norm[i] = w * normalize
if norm[i] < 1 then
table.insert(small_stack, i)
else
table.insert(big_stack, i)
end
end

local prob = {}
local alias = {}
while small_stack and big_stack do -- both non-empty
small = table.remove(small_stack)
large = table.remove(big_stack)
prob[small] = norm[small]
alias[small] = large
norm[large] = norm[large] + norm[small] - 1
if norm[large] < 1 then
table.insert(small_stack, large)
else
table.insert(big_stack, large)
end
end

for _, v in ipairs(big_stack) do prob[v] = 1 end
for _, v in ipairs(small_stack) do prob[v] = 1 end

self.__index = self
return setmetatable({alias=alias, prob=prob, n=#weights}, self)
end

function alias_table:__call()
local index = math.random(self.n)
return math.random() < self.prob[index] and index or self.alias[index]
end

sample = alias_table:new{10, 20, 15, 2, 2.3, 130}
print(sample())
``````
3 Likes

Can’t seem to get this working, maybe I’m doing something wrong?
Code returns nothing.

``````function WeightedRandom.RandomFromWeightedTable(OrderedTable)
local Weight = 0

for _, Chance in pairs(OrderedTable) do
Weight += (Chance * 10)
end

local RanNumber = math.random(1, Weight)

Weight = 0
for Piece, Chance in pairs(OrderedTable) do
Weight += (Chance * 10)

if Weight >= RanNumber then
return OrderedTable
end
end
end
``````

Could you give me the code in a function format?

You arent returning anything.

(30)

3 Likes

Yeah, he ended up solving it after posting that on another post

1 Like

Got something working, here’s something that works for me if anyone needs it.

I’m using 0.01 - 0.001 chances and they don’t seem to work (Nevermind, I fixed it by increasing the multipler (10) to 10000