Consistently get random selections

I’m trying to make a pizza minigame, that selects either 0, 1, 2, 3 toppings to place on each pizza, but I’m not sure how to efficiently make it random on if it picks none, or 3 toppings, etc. I’ve got sauces done, as it will just pick 1 of 3.

local function setPizzaData()
    local Toppings = {'Pepperoni', 'Mushroom', 'Olives', 'Pepper'}
	local Sauce = math.random(1, {'Tomato', 'Hot', 'Pesto'})
	local RandomToppings
	
	return Sauce, RandomToppings
end

So basically, there’s 4 toppings to choose from. So RandomToppings could be none, or it could just be 1 topping picked at random, say Mushroom

local RandomToppings = {'Mushroom'}

Or it could pick 3 at once

local RandomToppings = {'Mushroom', 'Pepperoni', 'Pepper'}

Get random number N from 0 to 3. Now generate a random permutation of the Toppings array. This can be done like that:

local amount = #Toppings;
for index = 1, amount do
    local newIndex = math.random(1, amount);
    swap(Toppings, index, newIndex) -- swap elements on these indexes (you need to implement that)
end

And now you can get the N first elements from the permuted array where N is the number we generated at the beginning.
You don’t have to permute the Toppings array. We can make an array of integers (let’s call it IntArray) from 1 do #Toppings, permute it and then take first N elements of Toppings[IntArray[i]].

local RandomToppings = {};
for i = 1, N do
    RandomToppings[i] = Toppings[IntArray[i]];
end

So the final code is:

function getRandomPermutation(n)
    local perm = {};
    for i = 1, n do
        perm[i] = i;
    end

    for index = 1, n do
        local newIndex = math.random(1, n);
        local temp = perm[index];
        perm[index] = perm[newIndex];
        perm[newIndex] = temp;
    end

    return perm;
end

function getRandomToppings(toppings)
    local N = math.random(0, #toppings);
    local RandomToppings = {};

    if N then
        local randPermutation = getRandomPermutation(#toppings);
        for i = 1, N do
            RandomToppings[i] = toppings[randPermutation[i]];
        end
    end

    return RandomToppings;
end
3 Likes

I had made some mistakes in the final code, now it’s ready and bugfixed.

local function getRandomPermutation(n)
    local perm = {};
    for i = 1, n do
        perm[i] = i;
    end

    for index = 1, n do
        local newIndex = math.random(1, n);
        local temp = perm[index];
        perm[index] = perm[newIndex];
        perm[newIndex] = temp;
    end

    return perm;
end

function getRandomToppings(toppings)
    local N = math.random(0, #toppings);
    local RandomToppings = {};

    if N then
        local randPermutation = getRandomPermutation(#toppings);
        for i = 1, N do
      		RandomToppings[i] = toppings[randPermutation[i]];
        end
    end

    return RandomToppings;
end

local function setPizzaData()
	local Toppings = {'Pepperoni', 'Mushrooms', 'Pepper', 'Olives'}
	local Sauces = {'Tomato', 'Hot', 'Pesto'}

	local RandomSauce = math.random(1, #Sauces)
	local RandomTopping = getRandomToppings(Toppings)
	
	return RandomSauce, RandomTopping
end

print(setPizzaData()) -- returns [2 table: 0x4700a0a31769e29b]

When I do

return RandomSauce, #RandomTopping

It’s telling me that sometimes there’s 4 toppings? The max should be 3
Hot 0

Pesto 0

Hot 3

Pesto 4

Because I made it to choose from all toppings

local N = math.random(0, #toppings);

You can modify that to

local N = math.random(0, 3);

And it will select 0 to 3 toppings from the set.

Also in your code you should change

local RandomSauce = math.random(1, #Sauces)

to

local RandomSauce = Sauces[math.random(1, #Sauces)]

To get the sauce not only a number.

How can I then go through each topping and set a text label to be it?

local Topping1 = Toppings:WaitForChild('Topping1')
local Topping2 = Toppings:WaitForChild('Topping2')
local Topping3 = Toppings:WaitForChild('Topping3')

function OrderBoardControl:Update(toppings)
	print(toppings) -- prints the table
end

Like go through, so if there’s 2 toppings, set Topping1 text to be the first topping, then Topping2 to be the second topping, etc. And then set Topping3 text to just be ‘’ as there’s no third topping

I would do something like this

local toppingTextLabels = {
    Toppings:WaitForChild('Topping1'),
    Toppings:WaitForChild('Topping2'),
    Toppings:WaitForChild('Topping3')
}

function OrderBoardControl:Update(toppings)
    local N = #toppings;
    local M = #toppingTextLabels;
    for i = 1, M do
        if i <= N then
            toppingTextLabels[i].Text = toppings[i];
        else
            toppingTextLabels[i].Text = 'No topping number ' .. i;
        end
    end
end
1 Like