As mentioned here, the only randomness facility in Lua is math.random.
What you are asking for is called weighted randomness -- you give weight to particular options to make them more likely.
Simple (Bad) Approach: Repeating items in a list
Picking a random thing from a list is pretty easy:
local list = {"red", "blue", "yellow"}
local choice = list[math.random(#list)]
If we want one to be more likely than another, it can just be in the list more times:
local list = {"red", "red", "red", "blue", "yellow"}
local choice = list[math.random(#list)]
For percentages, you should probably make loops to fill your list:
local list = {}
local chances = {}
chances[BrickColor.new("Purple")] = 20
chances[BrickColor.new("Bright blue")] = 50
chances[BrickColor.new("Bright red")] = 30
for thing, percentage in pairs(chances) do
for i = 1, percentage do
table.insert(list, thing)
end
end
local choice = list[math.random(#list)]
This is, of course, very silly.
A bigger problem is that you can't easily use fractional percentages (e.g., 12.37% of the time would require 1000 element list while 12.1337% a 100k list), and you can't do irrational percentages (this is actually a problem -- think picking randomly based on distances between things)
A solution
Going back to the list of 5. What exactly does it mean to repeat red to get the right percentage?
list = {"red", "red", "red", "blue", "yellow"}
index = math.random(#list)
- if
index is 1, 2, or 3, then you get "red"
- if
index is 4, then you get "blue"
- if
index is 5, then you get "yellow"
Let's use math.random() with no arguments, and consider the equivalent:
- if
index is 0 -- 0.6, then you get "red"
- if
index is 0.6 -- 0.8, then you get "blue"
- if
index is 0.8 -- 1, then you get "yellow"
The ranges are not very neat. Let's subtract the start from each:
- if
index - 0 is 0 -- 0.6, you get "red"
- if
index - 0.6 is 0 -- 0.2, you get "blue"
- if
index - 0.8 is 0 -- 0.2, you get "yellow"
This is super convenient, because each range is now [0, chance]! That means we just need to know what we're subtracting by.
But that's pretty easy to see, too. It's the sum of all of the previous chances. In other words, our loop will look like this:
- for each
chance and thing
if index < chance then
index = index - chance
alternatively, in a slightly cuter wording,
- for each
chance and thing
index = index - chance
if index < 0 then
This is example assumed index was originally between 0 and 1. The key is that it's between 0 and the sum of all chances.
Thus, the code looks something like this:
local sum = 0
for thing, chance in pairs(chances) do
sum = sum + chance
end
local index = math.random() * sum
local choice
for thing, chance in pairs(chances) do
index = index - chance
if index <= 0 then
choice = thing
break
end
end
1 comment
Don't mind me, I'm just bookmarking this post cuz it's too useful