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
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
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
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
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.
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.
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.