How to prevent math.random from picking the same map

● Hey! So basically, I’m making a game where it will choose random obby maps and you will have you reach the end to win. So far, the game is finished and everything works perfectly fine EXCEPT that the game sometimes chooses the same previous map, or it doesn’t choose a specific map at all throughout the entire playtime. This is kind of annoying because when my friends play it, they often get bored of playing the same map over and over again, sometimes It even chooses 5 same maps in a row even though there are 8 maps already.

● I believe It’s the math.random. Well, they say It is completely random but I don’t think it is that random. I’ve tried looking for solutions for 2 days and none of the topics that I’ve found seem to be related to this. So is there happen to be a way to modify the code lines a bit so that they will feel more random? Or to make it choose all the maps once by once without repeating the same map and then when it chooses the last map it redos the whole progress again?

local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

Maps = ServerStorage:WaitForChild('Maps'):GetChildren()
Text = ReplicatedStorage:WaitForChild('IntermissionText')

while true do
	local Countdown = 15

	repeat wait(1)
		Countdown = Countdown - 1

		Text.Value = 'Intermission : '..Countdown
	until Countdown <= 0

	

	Text.Value = 'Selecting Map'

	local ChosenMap = Maps[math.random(1, #Maps)]:Clone()
	
	local MapTeleport = ChosenMap.SpawnLocation

– Every help is appreciated!

6 Likes

Store the previous map in a variable, then check if map.random selects the previous and if it does pick another again. Once it picks a new map set the previous variable to the new map.

2 Likes

I have had the same problem a while back, here is the post I made to help solve the problem. Looking back it’s super simple but I had no idea then.

1 Like

What I do with random selection for my game is have a “Reference” table, which is all the items you want to randomize, and then create a second table to basically read from the reference table and then be used for actually picking the random values.

local referenceTable = {
"String",
"Hello",
"Cool"
}
local valuesToChoose = {}

After that, you want to basically:

  • Clone every item into the second (empty) table (so it looks identical)
  • Before choosing a value, check to make sure the second (to choose from) table isn’t empty. If it is empty, reload it from the reference table
  • Then, choose your random value, and then delete it from the second (choosing) table

I use this because it seems to be the easiest way to visualize what hasn’t been chosen, and it’s pretty easy to implement.

1 Like

You want “pseudo random.” Random without repeats.

Pick 2 prime numbers. Lets say, 7 and 5. “5” is the number of maps to choose from. If there are only 4? That’s fine, let the 5th be popular vote. Here we go:

Multiples of 7:
7,14,21,28,35,42,49,56,63,70

Multiples of 7, modulus 5:
2,4,1,3,0,2,4,1,3,0

Notice it’s a pattern, looks random, and everything gets selected once. The trick is, you can’t use 7 more than 5 times, or its a pattern. You switch to a different prime. The second prime will always cycle through the first prime without repeats.

So what you do:

  1. pick your first prime based on maps. A
  2. pick a different prime. B
  3. cycle A times through multiples of B, modulus A
  4. pick a new B

The modulus operator is “%”
27 % 7 = 6

1 Like

You would do the method I call “patterning”

For example, pick a number divisible by 2 (even number), so check if it has decimals if it picks an odd number(has decimals), redo the process

Now the next time you would want to pick the odd number, so do the complete opposite, if there’s no decimals, redo the process.

And so on.

Or, an easier method I call is a “temporary blacklist”

So basically, the first time you math.random you wanna store the number in a value to “blacklist” it

Now, the second time is if the math random equals the blacklisted number, redo math.random process

If success, replace the blacklisted number with the current selected number.

1 Like

This is an example of how to not get the same random result twice in a row. My method proves to work in practically anything - Map selecting, random players, music pickers, etc.

You can implement the code below into yours. It’s a pretty simple concept

local stages = somewhere:GetChildren()

local currentMap = nil
local previousMap = nil

repeat
    currentMap = stages[math.random(1,# stages)]
    wait()
until currentMap ~= previousMap
previousMap = currentMap
7 Likes

I do not recommend this solution.

For some weird reason, my random generator picks the same number many times in a row and it caused a big performance decrease. Even though the chances are really rare that you can get the same exact map infinitely, you still don’t want to loop to go on for a long time.

This is something I made, where it has more than one random generating but it will never cause a performance drop like repeat which is possible.

(It’s kind of written ugly with ands and ors. It’s not that complicated, I just decided to make one-line if statements.)

local LastIndex: number?

local function RandomNewElement<T>(array: { [number]: T }, seed: number?): T
	local RNG = Random.new(seed)

	if LastIndex == nil then
		LastIndex = RNG:NextInteger(1, #array)
		return array[LastIndex]
	end

	local firstSelectionIndex = ((LastIndex == 1) and 2 or (RNG:NextInteger(1, LastIndex - 1)))
	local secondSelectionIndex = ((LastIndex == #array) and (#array - 1) or (RNG:NextInteger(LastIndex + 1, #array)))

	-- Range
	local randomSelectionIndex = (
		(LastIndex == 1 or LastIndex == #array) and (RNG:NextInteger(firstSelectionIndex, secondSelectionIndex))
		or ((RNG:NextInteger(1, 2) == 1) and firstSelectionIndex or secondSelectionIndex)
	)

	LastIndex = randomSelectionIndex

	return array[LastIndex]
end

Since I used this code, there was never a big pause in my game when the map was randomly selected. A new map was always being randomly selected, and the performance was consistent in all of the decisions.

Just to mention, this won’t work if the array is not fixed.