Go through a table, and assign random elements to each player?

As my title suggests, I want to go through a table of players, and send information about a random player to another random player with no repeats and no pairs (So the same name isn’t assigned to itself). I’ve got the networking code working, but I’m unsure on the random assigning part. Here is my function so far:



	function SetKilling()
		playing = shuffleArray(playing)
		
		for k, v in pairs(playing) do
			v:SetNetworkedString( "Target", table.Random( playing ) )
		end
	end


By no repeats do you mean not sending a players information more then once? If that is the case do you NEED to have no repeats? Wouldn’t that also be impossible if there was a odd number of players in the server?

I think you may not understand exactly what I mean. I’ve just quickly produced some quick illustrations to hopefully better show what I mean:

The only difference to that is the player order is scrambled (so more like player 7, player 2, player 6 etc. rather than player 1, player 2, player 3 etc.)

Basically whenever you need to assign the information, you choose the name, etc. with table.Random (from the table, if that is that you are doing), and then remove that same exact element. So what you could do is pre-choose the variable such as

[lua]local random_identity = table.Random(playing);
setIdentity(ply, random_identity);
table.RemoveByValue(playing, random_identity);[/lua]

That way it’s the same across the board. And then each new round just reload the table to include the old ones.

Ok thanks, how can I make sure that the player doesn’t get picked as himself though? So Roboguy99 isn’t Roboguy99? Would it be like:


 
if target == playing[k] then
    SetKilling()
    return end


If you’re making sure the name isn’t the same, just check ply:Nick() with the random variable, if it is just reassign it.

Sorry - stupid question coming right up: this code is server-side, so where do I get the player from? Is it v in the for loop or something?

Is this what you mean?

Every player is assigned a target, that is not themselves AND hasn’t already been taken by another player, if so, here’s what I used in the picture, if you need anything explained, don’t be afraid to ask :slight_smile:

[lua]
validTargets = {}
TargetList = {}

function assignTarget( ply )
//Remove the player being assigned from the table
local targets = table.Copy( validTargets )
table.RemoveByValue( targets, ply )

//Choose a random player to be this players target
local target = table.Random( targets )
TargetList[ply] = target
table.RemoveByValue( validTargets, target )

end

function assignTargets()
table.Empty(validTargets)
table.Empty(TargetList)
validTargets = player.GetAll()
for k,v in pairs(player.GetAll()) do
assignTarget(v)
end
end

concommand.Add( “testHits”, function()
assignTargets()
PrintTable(TargetList)
end )
[/lua]

Well, if you’re assigning each player a variable I assume you are doing a for loop with each player? So just use the target there.

.
Yes, this is exactly what I mean! Thanks! I’ll play around with it and come back here if I need help.

[editline]8th June 2014[/editline]

Ok I need help :pwn:

Here is my code (all server-side):



include("roundbegin_shd.lua")

TargetList = {}

function setupPlayers()
    playing = getPlaying()
    
    GiveDefaultWeapons()
    SetColours()
    RunConsoleCommand("ex_assigntargets")
end

function GiveDefaultWeapons()
    
    for k, v in pairs(playing) do
        playing[k]:StripWeapons()
        playing[k]:StripAmmo()
        playing[k]:Give("m9k_fists")
    end
end

function SetColours()
    
    for k, v in pairs(playing) do
        playing[k]:SetPlayerColor(Vector(math.random(), math.random(), math.random()))
    end
end

function assignTarget(ply)
	//Remove the player being assigned from the table
	local targets = table.Copy(playing)
	table.RemoveByValue(targets, ply)
	
	//Choose a random player to be this players target
	local target = table.Random(targets)
	TargetList[ply] = target
	table.RemoveByValue(playing, target)
end

function assignTargets()
    table.Empty(playing)
	table.Empty(TargetList)
	playing = getPlaying()
    playingAll = getPlaying()
	for k,v in pairs(playingAll) do
		assignTarget(v)
	end
	PrintTable(TargetList)
end


function getPlaying()
    local allPlys = player.GetAll()
    local players = {}
    
    for k, v in pairs(allPlys) do
        if allPlys[k]:Team() == TEAM_PLAYING then players[k] = allPlys[k] end
    end
    
    return playing
end

function beginRound()
    setupPlayers()
end

function sendPlaying()
    net.Start("sendPlaying")
        net.WriteTable(playing)
    net.Broadcast()
end

concommand.Add("ex_roundbegin", beginRound)
concommand.Add( "ex_assigntargets", function() 
	assignTargets()
end )


As far as I can work out, the table TargetList is empty (the function is definitely run because I put some prints in there to test it, but the table is not printed). Any idea why?

You removed the global table at the top. Try adding this to the top. If not, then just use the code I provided, and don’t change the names? :v:
[lua]
playing = {}
[/lua]

I updated my code to show you everything. Is that line 100% necessary?

Well, in my example, it was used as a global table, so yes. Re-copy EXACTLY what I put, the only variable you should want to touch is the TargetList table because that holds the final data. What are you trying to accomplish next?

I’ve copied your code exactly and it prints nothing, also I’m getting this error now:



[ERROR] gamemodes/example/gamemode/roundbegin.lua:13: bad argument #1 to 'pairs'
 (table expected, got nil)
  1. pairs - [C]:-1
   2. GiveDefaultWeapons - gamemodes/example/gamemode/roundbegin.lua:13
    3. setupPlayers - gamemodes/example/gamemode/roundbegin.lua:6
     4. unknown - gamemodes/example/gamemode/roundbegin.lua:68
      5. unknown - lua/includes/modules/concommand.lua:69


Maybe it prints nothing because I’m currently testing this alone?

Next I’m going to use the target assigned to each player to update a HUD display and check if when the player kills someone it’s the right person (that sorta thing).

I just tried testing with 2 people - it prints the table correctly.

[editline]8th June 2014[/editline]

Ok I need help client-side now too :pwn:

Hopefully my code sorta explains what I’m trying to do. How do I get the target out of the table by putting in a player?



function getKillingFriendlyName(ply)
    local TargetList = ply:GetNetworkedString("Target")
    
    local Target = TargetList[ply] //Obviously doesn't work. How do I do such a thing?
    return Target:Nick()
end


To give the player their Target you would do something as follows:
Server Side
[lua]
util.AddNetworkString( “playerTarget” )

function SyncTargets()
for k,v in pairs(TargetList) do
net.Start( “playerTarget” )
net.WriteEntity(v)
net.Send( k )
end
end
[/lua]

Clientside
[lua]
net.Receive( “playerTarget”, function( len )
local temp = net.ReadEntity()
if temp != nil and IsValid(temp) then
TargetPlayer = temp
end
end )
[/lua]

Then on on your HUD for example, you would use TargetPlayer:Nick() to get their name.

Thanks!

[editline]9th June 2014[/editline]

Ok so when the players get assigned to eachother, not everyone is always assigned (the large arrow in my diagram is not present I think). I believe this is because each person is removed after being picked. I tested it with my friend, and he was my target but he got no target. Any help?



function assignTarget(ply)
	//Remove the player being assigned from the table
	local targets = table.Copy(validTargets)
	table.RemoveByValue(targets, ply)
	
	//Choose a random player to be this players target
	local target = table.Random(targets)
	TargetList[ply] = target
	table.RemoveByValue(validTargets, target)
end

function assignTargets()
	table.Empty(validTargets)
	table.Empty(TargetList)
	validTargets = playing
	for k,v in pairs(playing) do
		assignTarget(v)
	end
    
    PrintTable(TargetList)
    SyncTargets()
end


What do you mean he didn’t have a target, do you mean, server side in the main table he hasn’t been assigned, or client side on his HUD he didn’t have a target?

Server-side. Sorry.

Well in the picture I posted above, it has all 16 players assigned, so you’ve changed something from what I have put.

I posted my exact code above, and I’ve checked the list of valid players, which is correct.