Team randomization

Hello! im trying to create a system where every 60 seconds, the teams are shuffled, (also resetting them). just need to know how i would do that?

1 Like

You can use a shuffling algorithm to shuffle the players.

local function shuffle(t)
	local j, temp
	for i = #t, 1, -1 do
		j = math.random(i)
		temp = t[i]
		t[i] = t[j]
		t[j] = temp
	end
end

Similar to cards, you get a list of players, shuffle them, then split it two.

local players = game.Players:GetPlayers()
shuffle(players)
for i,v in pairs(players) do
	if i <= #players/2 then -- first half of the players
		v.TeamColor = BrickColor.new("Bright blue")
	else -- second half
		v.TeamColor = BrickColor.new("Bright red")
	end

	v:LoadCharacter() -- reset
end

This code would not work.

  1. :GetPalyers() returns a table, not a dictionary. You iterate tables with ipairs().
  2. math.random() requires two parameters, a minimum and maximum.
  3. ‘function shuffle()’ does not a return a value, nor does it modify a non-local variable.
  4. The first value returned by pairs() is the key of the value, not an index.

Here’s a piece of code that would work:

function RandomizeTable(rt_Table)
	local rt_Shuffled = {}
	while #rt_table > 0 do
		if #rt_Table == 1 then --Not sure if math.random(1,1) would throw an error. Remove this if statement if it doesn't.
			table.insert(rt_Shuffled,rt_Table[1])
			table.remove(rt_Table,1)
		else
			local rt_RandomNumber = math.random(1,#rt_Table)
			table.insert(rt_Shuffled,rt_RandomNumber)
			table.remove(rt_Table,rt_RandomNumber)
		end
	end
	return rt_Shuffled
end

function TeamScramble()
	--//Get and randomize list of players
	Players = RandomizeTable(game.Players:GetPlayers())
	
	--//Iterate through list.
	for i,vPlayer in ipairs(Players) do

		if i % 2 == 1 then --//Check via even or odd index.
			--//Assign to team 1
		else 
			--//Assign to team 2
		end

		vPlayer:LoadCharacter() -- reset
	end
end

i have about 5 teams, is there a way i could make the max amount of players on each team custom?

You’d need more conditional statements if you have different amounts of max members per team. Something like:

--//Using tables to reduce line count.
Teams = {team1,team2,team3,team4,team5}

for i,vPlayer in ipairs(Players) do
	local selectedTeam = (i % #Teams) + 1
	--//Team assignment.
	if Teams[SelectedTeam]  < MaxPlayers then --Change to max players per specific team.
		table.remove(Teams,SelectedTeam)
	end
	--Respawn Player
end

what about just making the max amount 1?

Why use teams at that point then?

im making a court game, i just need a team shuffling system every round

If the special teams are only one person, you can just select random players and then assign everyone else to the jury.

I will include a response just to address the points and give feedback:

  1. ipairs and pairs are technically distinct. However, in this scenario it functions identically. But yes, you’d use ipairs() in an array.
  2. math.random(x) is a valid parameter which will generate a random number between 1 to x
  3. shuffle() does not return a value because it takes advantage of pass by reference. The table passed as the parameter is the original table, and is modified directly by the function.
  4. same as point 1.

can you clarify on this and provide an example? Like a team with 1 member, a team with 3, and a team with 5?

1 Like

got it, how would you use math.random for it though?

You can get a random element of a table by doing ‘MyTable[math.random(1,#MyTable])’. It works by selected a random index of the table.

local players = game:GetService("Players")
local teams = {
    Defendant = game:GetService("Teams").Defendant,
    Lawyer = game:GetService("Teams").Lawyer,
    Judge = game:GetService("Teams").Judge,
    Witness = game:GetService("Teams").Witness
}
local juryTeam = game:GetService("Teams").Jury
local selectionTime = 10
local resetTime = 60
local currentSelectionTime = 0
local currentResetTime = 0
local selectedPlayers = {}

local function SelectPlayers()
    for _, player in ipairs(players:GetPlayers()) do
        player.Team = juryTeam
    end
    
    selectedPlayers = {}
    
    local availableTeams = {}
    for name, team in pairs(teams) do
        if team ~= juryTeam then
            table.insert(availableTeams, name)
        end
    end
    
    for i = 1, 5 do
        local randomIndex = math.random(1, #availableTeams)
        local selectedTeamName = availableTeams[randomIndex]
        local selectedTeam = teams[selectedTeamName]
        
        local allPlayers = players:GetPlayers()
        local numPlayers = #allPlayers
        local randomPlayerIndex = math.random(1, numPlayers)
        local player = allPlayers[randomPlayerIndex]
        
        if not selectedPlayers[player] then
            player.Team = selectedTeam
            table.insert(selectedPlayers, player)
            table.remove(availableTeams, randomIndex)
        end
    end
end

game:GetService("RunService").Stepped:Connect(function(_, dt)
    currentResetTime = currentResetTime + dt
    if currentResetTime >= resetTime then
        currentResetTime = 0
        SelectPlayers()
    end
    
    currentSelectionTime = currentSelectionTime + dt
    if currentSelectionTime >= selectionTime then
        currentSelectionTime = 0
        SelectPlayers()
    end
end)

would this work?

  1. There is no defined order when using pairs(). Roblox documentation also reccomends using ipairs() for arrays.
    2.You are correct about 2 and 3 actually. However, the function itself should probably not be local.

It’s got a lot of inefficiencies, but it should work.

A few things I want to clarify:

  1. You actually don’t need to use pairs or ipairs anymore. You can use general iteration and is more performant than both iterator functions. (Syntax - Luau)
  2. There actually is a slight performance increase in using local functions in top-level stacks because of how it traverses through the stacks internally. (Any advantage in declaring a function as local? - #31 by rogeriodec_games)

Other than that, I don’t know why you are opting for a RunService method of shuffling players. Here is a script with adjustable settings that just relies on minimal resources.

--!strict

-- Services
local Players = game:GetService("Players")
local Teams = game:GetService("Teams")

-- Round Configuration
local MINIMUM_PLAYERS: number = 5			-- Minimum amount of players
local SELECTION_TIME: number = 10			-- Time before shuffle starts
local RESET_TIME: number = 10				-- Time before game resets
local SHUFFLE_EVENLY: boolean = true		-- Determines whether to shuffle evenly (for non-guaranteed teams)
local RESPAWN_ON_SHUFFLE: boolean = true	-- Determines whether to respawn players on shuffle
local VERBOSE: boolean = true				-- Determines whether to output game status on console

-- Team Configuration
local TEAM_LIST: TeamList = {
	[Teams.Judge] = {
		MAX_PLAYERS = 1,
		GUARANTEED = true
	},
	[Teams.Defendant] = {
		MAX_PLAYERS = 1,
		GUARANTEED = true
	},
	[Teams.Lawyer] = {
		MAX_PLAYERS = 1,
		GUARANTEED = true
	},
	[Teams.Witness] = {
		MAX_PLAYERS = 10,
		GUARANTEED = false
	},
	[Teams.Jury] = {
		MAX_PLAYERS = 10,
		GUARANTEED = false
	},
}

-- Types
type TeamList = {
	[Team]: TeamSettings
}

type TeamSettings = {
	MAX_PLAYERS: number,
	GUARANTEED: boolean
}

-- Function to print if verbose is set to true
-- This will not stack overflow with this pattern
local print = function(...: any): ()
	if VERBOSE == true then
		print(...)
	end
end

-- Function to wait for minimum players
local function WaitForMinimumPlayers(): ()
	if #Players:GetPlayers() < MINIMUM_PLAYERS then
		print(`Waiting for at least {MINIMUM_PLAYERS} player(s)...`)
		
		repeat
			task.wait()
		until #Players:GetPlayers() >= MINIMUM_PLAYERS
	end
end

-- Function to set all players to a team
local function ResetTeams(team: Team?): ()
	for _, player: Player in Players:GetPlayers() do
		player.Team = team
	end
end

-- Function to shuffle players
local function ShufflePlayers(): ()
	local guaranteedTeams: {Team} = {}
	local guaranteedTeamsCount: number = 0
	local shuffledTeams: {Team} = {}
	local shuffledTeamsCount: number = 0
	
        -- Setup our team arrays with x amount of teams
	for team: Team, teamSettings: TeamSettings in TEAM_LIST do
		if teamSettings.GUARANTEED == true then
			guaranteedTeamsCount += 1
			
			for _ = 1, teamSettings.MAX_PLAYERS do
				table.insert(guaranteedTeams, math.random(1, #guaranteedTeams + 1), team)
			end
		else
			shuffledTeamsCount += 1
			
			-- Only insert one so we can shuffle
			-- with our specified settings
			table.insert(shuffledTeams, math.random(1, #shuffledTeams + 1), team)
		end
	end
	
	-- Shuffle our non-guaranteed teams
	local nextTeamIndex: number = 1 -- used for even shuffling
	
	for _ = 1, #Players:GetPlayers() - guaranteedTeamsCount do
		if SHUFFLE_EVENLY == true then
			-- Insert into the shuffled teams array via alternating
			table.insert(shuffledTeams, shuffledTeams[nextTeamIndex])
			nextTeamIndex += 1
			
			if nextTeamIndex > shuffledTeamsCount then
				nextTeamIndex = 1
			end
		else
			-- Insert into the shuffled teams array via random
			table.insert(shuffledTeams, shuffledTeams[math.random(1, shuffledTeamsCount)])
		end
	end
	
	-- Shuffle our players and assign them a team
	local shuffledPlayers: {Player} = {}
	
	for _, player: Player in Players:GetPlayers() do
		table.insert(shuffledPlayers, math.random(1, #shuffledPlayers + 1), player)
	end
	
	for _, player: Player in shuffledPlayers do
		if #guaranteedTeams > 0 then
			player.Team = guaranteedTeams[1]
			table.remove(guaranteedTeams, 1)
		else
			player.Team = shuffledTeams[1]
			table.remove(shuffledTeams, 1)
		end
		
		if RESPAWN_ON_SHUFFLE == true then
			player:LoadCharacter()
		end
	end
end

-- Loop game
while true do
	-- Reset team to Jury
	print("Resetting teams back to jury...")
	ResetTeams(Teams.Jury)
	-- Wait for minimum players
	WaitForMinimumPlayers()
	-- Start selection timer
	task.wait(SELECTION_TIME)
	-- Shuffle players
	print("Shuffling players...")
	ShufflePlayers()
	-- Start reset timer
	task.wait(RESET_TIME)
end
3 Likes

the performance of iteration using generalized iteration, pairs and ipairs is comparable

The performance is generally the same.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.