Selecting half of the players in a for loop

Hi, I was wondering how this code can choose half of the players as murders and the other half as sheriff. Here is my code:

function module.ChooseMurderers(players)
	local RandomObj = Random.new()

	local chosenMurderer = players[RandomObj:NextInteger(1, #players)]

	return chosenMurderer
end
function module.ChooseSheriffs(players)
	local RandomObj = Random.new()

	local chosenSheriff = players[RandomObj:NextInteger(1, #players)]

	return chosenSheriff
end

You could do something like

local players = game:GetService("Players"):GetPlayers() -- players in-game

local sheriffs = {} -- sheriffs table
local murderers = {} -- murderers table

local totalPlayers = #players -- total number of players

for _, plr in pairs(players) do -- loop through players
   if (#sheriffs <= totalPlayers/2) and not table.find(sheriffs, plr)  and not table.find(murderers, plr) then 
      -- if the length of the sheriffs table is less than half of the total amount of players and the player isn't already
      -- in the sheriff or murderer table then pass

      table.insert(sheriffs, plr) -- add player to the table
      -- code here
   elseif #sheriffs >= totalPlayers/2 then -- check if the table is greater than or equal to half of the players
      break -- end the loop
   end
end

-- basically same exact thing but for murderers
for _, plr in pairs(players) do
    if (#murderers <= totalPlayers/2) and not table.find(sheriffs, plr) and not table.find(murderers, plr) then
       table.insert(murderers, plr)
       -- code here
    elseif #murderers >= totalPlayers/2 then
       break
    end
end)

not sure if it’ll be a 100% accurate thing however, but this is just to give a sense of what something like this would look like.

For your code, I would suggest looping through the Players in the game, and add random ones to a table then check if the length of the table is half of the total number of players in-game and if the player isn’t already in the table. Then insert the remaining players into the other table

2 Likes

Will this work if there is an odd number of players like 19, 17, 15, etc. players?

much more concise!

function module.Choose(plrs)
	local murderers,sheriffs={},{}
	while #plrs~= 0 do
		local pos=math.random(1,#plrs)
		if #murderers> #sheriffs then
			table.insert(sheriffs,plrs[pos])
		else
			table.insert(murderers,plrs[pos])
		end
		table.remove(plrs,pos)
		wait()
	end
	return murderers,sheriffs
end
2 Likes

I don’t believe so, there would be 1 extra player on either faction since it’s an odd number

What should I do in that case? Just add 1 player to one of the teams? How would I code that?

1 Like

The second solution I offered

should (maybe) cover that, as it just throws the other players into the other faction after checking once since the script would assume that there’s an even amount of players on both sides

I don’t think your code would do something so nice, because:

if (#sheriffs ~= totalPlayers/2)

is always true for an odd number of players!

1 Like

Thank you for pointing that out, I will fix it

Also, there is really no need to do rejection sampling for such a simple case. The usual solution for something like this is to just shuffle the array of players and then take the first N/2 as the murderers and the rest as sheriffs. Whether you round N/2 up or down for an odd number of players to have either an extra murderer or extra sheriff is up to you to do what works best for your gameplay.

Shuffling an array with something simple like Knuth-Fisher-Yates (which is like 3 lines of code) has a fixed runtime, whereas rejection sampling does not, because of all the retries.

1 Like

FWIW, here is the basic code I use to shuffle all kinds of stuff (Club RAVEN playlists, map voting in Frogge, etc.):

local RNG = Random.new()

local function FisherYatesShuffle(array)
	local n = #array
	for i = 1, n-1 do
		local j = RNG:NextInteger(i,n)
		array[i], array[j] = array[j], array[i]
	end
end

local testArray = {1,2,3,4,5,6,7,8,9,10}
FisherYatesShuffle(testArray)
print(testArray)

In your case, you’d just shuffle the array of players, and then make the first half of them murderers.

Your new code is only setting the sheriffs, not any murderers

you can try my code above, note that she >= mur

I may be wrong but this may work

For I,_ in pairs (game.Players:GetPlayers())do

      if I %2! == 0 then 
           --Place in team 1 
      else 
           --Place in team 2
      end
end

I’ve just scripted up the team selection and it works, it’ll just look at if the sheriffs and murders and see if they are equal. This game mode will only be playable if the number of players is even.

1 Like