How to Prevent math.random from picking the same player

So basically Im creating a Arena type of game where it picks 2 players but the problem I’m having is that its picking the same player

	local player1 = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())]
	local player2 = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())]

Is there a way to fix this?

Create a table with unpicked players, and make math.random pick out of the table. Once the player has been picked, remove them using table.remove. Example:

local tbl = {}
local plr1
local plr2
local function doFor(num)
	if num == 1 then
		plr1 = tbl[math.random(1, #tbl)]
		for i = 1, #tbl do
			if tbl[i] == plr1 then
				table.remove(tbl, i)
			end
		end
	elseif num == 2 then
		plr2 = tbl[math.random(1, #tbl)]
		for i = 1, #tbl do
			if tbl[i] == plr2 then
				table.remove(tbl, i)
			end
		end
	end
	
end
game.Players.PlayerAdded:Connect(function(plr)
	for _, i in pairs(game.Players:GetPlayers()) do
		table.insert(tbl, i.Name)
	end
	doFor(1)
	if #game.Players:GetPlayers() == 2 then
		doFor(2)
	end
	print(plr1, plr2) -- Doqee nil (only 1 person is in the server)
end)

edit - fixed the issues, ty for the replies that noticed my errors
edit2 - use the method below instead, hence its more tidy and efficient

1 Like

doFor(plr1) will not tell the function to set the random player as the value of plr1. Instead, it will just call the function, giving the value of plr1 (which is nil) as an argument. the player will only be the value of the function’s parameter which will be garbagecollected soon after the function has finished running. You should add return var in the function and when calling it, do

plr1 = doFor()
plr2 = doFor()

I think you should put the math random number with a 2 and not a 1 then make an if statement of math random equals 1 and if it equals 2.

1 Like

08:58:26.883 - ServerScriptService.Script:8: invalid argument #2 to ‘random’ (interval is empty)

1 Like

Alright this might not work because I can not test it but you can make a variable for the math random from 1 to 2 for the numbers then make a local function for the two players.

local player1 = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())]
local player2 = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())]

if player2 == player1 then
   local x = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())]
   repeat wait() x = game.Players:GetChildren()[math.random(1,#game.Players:GetPlayers())] until x~= player1 -- this should be fast 
   player2 = x
end

Just an okay method above… If you are talking about the player being picked every time they join that’s a whole other issue, on line one you would write:

math.randomseed(tick())

The first code picks 2 players, checks if player one is player two, if so then a variable is defined and looped until its not player1 then sets player2 to itself

2 Likes

Its as simple as doing this:

local Players = game:GetService('Players'):GetPlayers()

local P1_Number = math.random(1, #Players)
local Player1 = Players[P1_Number]

table.remove(Players, P1_Number)

local P2_Number = math.random(1, #Players)
local Player2 = Players[P2_Number]

I am a little confused why you need a long script to do this.
Also, @Doqee

for _, I in pairs(game.Players:GetPlayers()) do
    table.insert(tbl, i.Name)
end

This bit of code can cause duplicates of names in a table. I suggest simply getting the player table by saying:

local PlayerTbl = game:GetService('Players'):GetPlayers()
1 Like

I can understand why you’re using a DoFor method, but there are other ways to do it as well. For example:

local ArenaTbl = {}
local PlayersTbl = game:GetService('Players'):GetPlayers()

function DoFor(Number)
     If PlayersTbl <= 0 then return nil end

     local PN = math.random(1, #PlayersTbl)
     ArenaTbl['Player' .. Number] = PlayersTbl[PN]

     table.remove(PlayersTbl, PN)
     return true
end

function GetArenaPlayers()
     PlayersTbl = game:GetService('Players')
     ArenaTbl = {}
     

     local S1 = DoFor(1)
     local S2 = DoFor(2)

      if not S1 then return end
      if not S2 then return end

      return ArenaTbl['Player1'], ArenaTbl['Player2']
end

local Player1, Player2 = GetArenaPlayers()

This script is a little bit cleaner and more concise. It also uses a lot less space.

2 Likes

If I got this How would I fetch the players name? should I say S1.Name?