How to fill a grid with random colours using percentages?

Hi, I’m looking to achieve a system that can create and fill a grid of parts that have random colours. I’ve figured out how to create the grid, but I only know how to use math.random() for the random colours.

So, for example, I could use math.random(1,3) if I had 3 colours.

But a problem with this is it is complicated and if I want to change the rarity of colours, it would be difficult to get right with math.random()

But I have thought of a solution and this is using percentages. So, say I could put in 3 variables which are 50% Red, 25% Green and 25% Blue. This would generate a grid with half the parts being red, a quarter being blue and the rest being green.

I hope I explained that well, and if you know how to do this, I would greatly appreciate it if you let me know.

Thanks!

Try searching around, this gets asked pretty often and there are already lots of good answer

math.randomseed(tick())

local rarities = {["red"] = {0, 49}, ["green"] = {50, 74}, ["blue"] = {75, 99}}

local function getRandomColorWeight()
	local randomNumber = math.random(0, 99)
	for colorName, rarity in pairs(rarities) do
		if randomNumber >= rarity[1] and randomNumber <= rarity[2] then
			return colorName
		end
	end
end

local randomColor = getRandomColorWeight()
print(randomColor)

What you’re looking for is known as the concept of weighted randomisation.

This isn’t actually that hard of a problem, but let’s simplify it a little bit first.
Instead of saying that green and blue have a 25% chance and red a 50% chance, let’s give green and blue a value of 1, and red a value of 2. This value will represent how many times the colour appears in our list, so currently it’d look like this: GBRR where G = green, B = blue, R = red.
If you now select a random value out of this list, you will have a greater chance of selecting red than green and blue.
A simple program that might achieve this could be written as follows, although I don’t recommend using it:

local list = {red = 2, green = 1, blue = 1}

local function selectItem(list)
  local newList = {}
  for color, count in pairs(list) do
    for i = 1, count do
      table.insert(newList, color)
    end
  end
  -- newList is now {"red", "red", "green", "blue"}

  local item = newList[math.random(#newList)]
  return item
end

print(selectItem(list))

This is actually what you want to achieve, but you can improve it a lot more.
Creating a new table, increasing it’s size everytime it gets filled, and moving all values inside can take a lot of time. Additionally, you’d also like to give items half the chance of being selected, and multiplying all values besides that one by 2 is simply tedious.

What you can do instead is count up all the values of each item, and generate a random number between 0 and that. After that, you can find the item that corresponds to that value.

local list = {red = 2, green = 1, blue = 0.5}
local function selectItem(list)
  local count = 0
  for _, value in pairs(list) do
    count += value
  end

  local number = math.random() * count
 -- math.random(x) generates a whole number between 0 and x
-- math.random() * x generates a more random number between 0 and x

  -- Select the item
  count = 0
  for item, value in pairs(list) do
    if (count < number) and (count + value >= number) then
      return item
    end
    count += value
  end
end

print(selectItem(list))

I have not tested this code, but this should return red 2 times as often as green, and green 2 times as often as blue.

Thanks for the help, managed to get the script working and it’s running very nicely. Seems pretty fast too