I have a map system for my game that cycles through a random map each time the round starts. I’ve tried countless different methods but I have no clue how to make the table that stores my maps (MapTable) pick a new random index from itself each time without repeating. I want the Table to cycle through all 20 maps without repeating a single one, and then restart.
maybe try something like this you need your maintable to stay same but setup a temp table as a random map is choosen just remove it from the table when it hits 0 or is empty then reset it again to your mainmaptable
local MainMapTable = {
1,2,3
}
local TempMapTable = {}
function ResetTempMaps()
TempMapTable = {}
for i, map in ipairs(MainMapTable) do -- setup a tempmaptable to remove maps from
TempMapTable[i] = map
end
end
function GetMap() -- this gets a new map each time
if #TempMapTable <= 0 then -- this can be called somewhere before calling getmap but it will reset the tempmaps table using the mainmaptable
ResetTempMaps()
end
local MapKey = math.random(1,#TempMapTable)
local Map = TempMapTable[MapKey] -- gets a temp map
table.remove(TempMapTable, MapKey) -- remove it from temp table so its not choosen again
return Map -- return it
end
local GameMaps={}
local function GetRandomMap()
if #GameMaps<1 then GameMaps=workspace.Maps:GetChildren() end -- Point this to your maps folder, Once GameMaps is empty is will refill with all maps
local Rnd=math.random(1, #GameMaps) -- Get a random number between 1 and maps not yet chosen
local NewMap=GameMaps[Rnd] -- Select your new map
table.remove(GameMaps, Rnd) -- Remove selected map from table so it can't be selected again
return NewMap -- returns the result
end
local NextMap=GetRandomMap()
I added your code to my script, and it seems to work at first but then I get repeating maps. After the “GetMap” function runs and it returns “Map” I added this code after the “end”
local NextMap=GetMap()
print(NextMap)
local map = NextMap:Clone()
Choose a random unchosen map, if all maps are chosen, refresh. This may cause a problem where if a map is the last unchosen map, it may be chosen first after the refresh, so you also check if it wasn’t previously chosen.
local maps = {} -- Insert maps
local chosenMaps = {}
local prevMaps = {}
local function RandomMap()
local remaining = #maps
-- Pick random map that is not previously chosen
local chosen = math.random(remaining)
local map = maps[chosen]
while table.find(prevMaps,map) do
chosen = math.random(remaining)
map = maps[chosen]
end
-- Mark as previously chosen
table.insert(prevMaps,1,map)
prevMaps[math.floor(#chosenMaps+remaining/2)] = nil
-- Remove in unchosen maps
table.remove(maps,chosen)
table.insert(chosenMaps,map)
if remaining == 1 then -- If all maps is chosen, refresh
maps, chosenMaps = chosenMaps, maps
end
return map
end
-- How to run
local nextMap = RandomMap()
I tested it and it doesn’t repeat unless all maps have been chosen.
the method is certainly not through the tables, but still it is short and simple
local maps=game.ReplicatedStorage.Maps -- maps folder
locql current=nil
local map
repeat wait()
map=maps:GetChildren()[math.random(#maps:GetChildren()]
until map.Name~=current
current=map.Name
puts the map into a variable if the map is not current, otherwise iterates over the new one and puts it into a variable
Are you sure there isn’t some other code interfering with the process? I just ran the code and it worked as expected:
local GameMaps={}
local function GetRandomMap()
if #GameMaps<1 then
print("No Maps in GameMaps - Refreshing..")
GameMaps=workspace.Maps:GetChildren()
end -- Point this to your maps folder, Once GameMaps is empty is will refill with all maps
local Rnd=math.random(1, #GameMaps) -- Get a random number between 1 and maps not yet chosen
local NewMap=GameMaps[Rnd] -- Select your new map
table.remove(GameMaps, Rnd) -- Remove selected map from table so it can't be selected again
return NewMap -- returns the result
end
for i=1, 20 do
local NextMap=GetRandomMap()
print("Map Chosen: "..NextMap.Name)
task.wait()
end
Output:
10:32:50.200 No Maps in GameMaps - Refreshing.. - Server - Script:6
10:32:50.201 Map Chosen: Map_04 - Server - Script:19
10:32:50.258 Map Chosen: Map_05 - Server - Script:19
10:32:50.570 Map Chosen: Map_03 - Server - Script:19
10:32:50.576 Map Chosen: Map_02 - Server - Script:19
10:32:50.607 Map Chosen: Map_01 - Server - Script:19
10:32:50.882 No Maps in GameMaps - Refreshing.. - Server - Script:6
10:32:50.882 Map Chosen: Map_04 - Server - Script:19
10:32:51.316 Map Chosen: Map_03 - Server - Script:19
10:32:51.356 Map Chosen: Map_01 - Server - Script:19
10:32:51.382 Map Chosen: Map_05 - Server - Script:19
10:32:51.402 Map Chosen: Map_02 - Server - Script:19
10:32:51.431 No Maps in GameMaps - Refreshing.. - Server - Script:6
10:32:51.431 Map Chosen: Map_05 - Server - Script:19
10:32:51.515 Map Chosen: Map_04 - Server - Script:19
10:32:51.537 Map Chosen: Map_03 - Server - Script:19
10:32:51.551 Map Chosen: Map_02 - Server - Script:19
10:32:51.566 Map Chosen: Map_01 - Server - Script:19
10:32:51.587 No Maps in GameMaps - Refreshing.. - Server - Script:6
10:32:51.587 Map Chosen: Map_05 - Server - Script:19
10:32:51.599 Map Chosen: Map_03 - Server - Script:19
10:32:51.616 Map Chosen: Map_01 - Server - Script:19
10:32:51.633 Map Chosen: Map_02 - Server - Script:19
10:32:51.650 Map Chosen: Map_04 - Server - Script:19
For clarity, there are just 5 folders in the Maps folder in my test.
local Game = game
local ServerStorage = Game:GetService("ServerStorage")
local MapsFolder = ServerStorage.Maps --Maps folder.
local RandomObject = Random.new()
while true do --Infinite loop.
local Maps = MapsFolder:GetChildren() --Array of maps.
repeat --Repeat loop.
local Map = table.remove(Maps, RandomObject:NextInteger(1, #Maps)) --Remove map from array and use it for a round.
--Round code here.
until #Maps == 0 --End loop when no more maps available.
end
Fairly trivial pseudo-code to help steer you in the right direction.
Sorry in advance for the late reply, I haven’t been able to get to my computer until now. (Also thanks to everyone who replied, I will test each code out to see if it fixes this problem)
Ok so the code works beautifully, only 1 problem. I want only one of the maps to spawn in for a round, and then the order continue 1 by 1 as each round ends. Currently they all spawn in at once, and it makes my game kinda laggy. Any suggestions?
This may look like a complicated article but it’s visualizations and math are very effecient. it will prevent stalling like a lot of recommendations here may.
We will be twisting a shuffle implementation into drawing from a deck of cards. The in-place shuffle we use is called Fisher-Yates.
Pros:
No infinite loops (very fast!)
No extra arrays/tables
local maps = {
"Big City",
"Desert",
"Jungle",
"Soup Isle",
}
local usedIndecies = 0
local function get_random_map(): string
-- all of our cards are "used" we reset the deck
if usedIndecies >= #maps then
usedIndecies = 0
end
-- we get how many cards are marked as "Used"
local unusedEnd = #maps - usedIndecies
-- we do not draw from the end, these are "Used" cards
-- as cards are drawn we shrink how many are available
local index = math.random(1, unusedEnd)
local gotItem = maps[index]
-- swap our selected item with our "used" end of deck
maps[index], maps[unusedEnd] = maps[unusedEnd], maps[index]
-- next draw cannot select the card we just swapped
usedIndecies += 1
return gotItem
end
Well, if your using my code example then you would remove the for i=1, 20 do loop, that was only added to show the function in action during many calls.
You would just use local NextMap=GetRandomMap() once before each round starts and clone/move the chosen map to the play area.
Thanks to everyone who replied! I’ve learned a ton from each one of you guys. Also thanks to Sunny_Bunny, the method works, I just had to rearrange my code a bid to fit it in properly. Appreciate the help guys