Let's say I had a block, and I wanted that block to be made into a random color. But I would like some colors to be more likely than others (this done accomplished through a table).
Purple_Chance = 20 Blue_Chance = 50 Red_Chance = 30 --paint block based on chance
Any help is appreciated (Wikis, other Q&A's) NOTE:The lua block is not meant to be taken too seriously, it's just to give an example to people who like their visuals.
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.
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)] -- 60% chance for red
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)
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)
index
is 1, 2, or 3, then you get "red"
index
is 4, then you get "blue"
index
is 5, then you get "yellow"
Let's use math.random()
with no arguments, and consider the equivalent:
index
is 0 -- 0.6, then you get "red"
index
is 0.6 -- 0.8, then you get "blue"
index
is 0.8 -- 1, then you get "yellow"
The ranges are not very neat. Let's subtract the start from each:
index - 0
is 0 -- 0.6, you get "red"
index - 0.6
is 0 -- 0.2, you get "blue"
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:
chance
and thing
if index < chance then
thing
index = index - chance
alternatively, in a slightly cuter wording,
chance
and thing
index = index - chance
if index < 0 then
thing
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 -- note: NOT math.random(sum). That will truncate the fractional part of sum local choice for thing, chance in pairs(chances) do index = index - chance if index <= 0 then choice = thing break end end