Weighted Probability and Luck Boosts

Hi! I’m currently trying to create a weighted probability system for my game. The game should select a random ore from the list of ores in a layer and then roll a random number to see what will be selected. My setup is ordered a little differently from normal weighted probability systems so that I could define the probabilities in a 1/n sort of fashion, since adding / removing weights would shift around the probability of everything else and start causing problems (so I guess it’s absolute instead of relative? I hope that’s the right word). The code I have is as follows:

local rng = Random.new()
function Mine.generateOre(layer: Layers.Layer, luck: number)
    local ores = layer.ores

    local yourFate = rng:NextNumber()

    for _, ore in ores do
        local chance = 1 / ore.Chance.Value * luck
        if yourFate < chance then
            return ore:Clone()
        end
        yourFate -= chance
    end

    return layer.stone:Clone()
end

The problem for me arises with the luck variable. Basically, the entire system works on the premise that all of the probabilities can fit on a 0-1 number line, and then said number line has a random point on it selected as the point that the “random” item ends up on. This layout is also completely random (as in unsorted, it’s always in the same order) in it’s order, so the first element could be a 1/55 while the second one is a 1/3 000 000. The luck variable is supposed to increase the odds of every ore by multiplying the probability (i.e. 1/55 * 5 = 1/11), but if one of the probabilities ends up causing the value to go above 1, it’s always selected, which means that whatever shows up in the “number line” is selected. I want the system, in this situations, to prioritize rarer ores over the less common ones, but I have no idea where to start with that. Any help is grealty appreciated!!

You can apply a weight to the different ores and adjust these weights based on the player’s luck instead. You’re right on that. Here’s how I would incorporate that:

local rng = Random.new()
function Mine.generateOre(layer: Layers.Layer, luck: number)
    local ores = layer.ores
    local totalWeight = 0  -- total weight

    -- Adjust weights based on luck
    for _, ore in pairs(ores) do
        ore.Chance.Value = ore.Chance.Value * (1+luck)  -- Increase weight by luck percent
        totalWeight = totalWeight + ore.Chance.Value
    end

    -- Get a random number between 0 and sum of all weights
    local yourFate = rng:NextNumber(0, totalWeight)

    -- Determine the ore's selection based on cumulative weight
    local accumulatedWeight = 0
    for _, ore in pairs(ores) do
        accumulatedWeight = accumulatedWeight + ore.Chance.Value
        if yourFate <= accumulatedWeight then
            return ore:Clone()
        end
    end

    return layer.stone:Clone()
end

I made it so your luck mechanic now acts as a percentage modifier to the weight of an ore, meaning, higher the luck, higher the chance of finding a rarer ore but without the chance overtaking 1. This will favor ores listed first if they have same probability as those listed after them, so I would recommend to solve this by shuffling the ores before running through them.

2 Likes