- Home /
Assign role randomly from array
I got the first section of the script figured out :
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class RandomRoleAssignment : MonoBehaviour {
public GameObject[] Players;
string[] possibleRoles = {"Citizen" , "Mafia"};
void Start()
{
Players = GameObject.FindGameObjectsWithTag ("Player");
AssignRole ();
}
void AssignRole()
{
int randomRoleIndex = UnityEngine.Random.Range (0, possibleRoles.Length);
string assignedRole = possibleRoles [randomRoleIndex];
for (int i = 0; i < Players.Length; i++)
{
print("Player " + i + " is named " + assignedRole);
}
}
}
this script finds all the players with the tag "player" and assigns it the same role. This isn't what I want it to do, I want it to randomly assign the players either citizen or mafia. Further I want there to always be a set number of players assigned as mafia (for example if there are 4 players then 1 must be a mafia, if there are 10 players then 2 have to be mafia etc)
Answer by fafase · Jun 08, 2019 at 03:31 PM
So basically you want 25% of your players to be mafia while the remaining 75% are citizen.
Best way is to leave it to probability:
if(Random.Range(0,100)< 25)
{
// Player is mafia
}
else
{
// Player is citizen
}
Now because probability is almost certain (it's math), this has to work. Though there is also a probability that you get 100% of one or the other (though extremely not probable).
You could convince yourself with something like this:
IEnumerator RandomCoroutine()
{
int mafia = 0; int citizen = 0; int total = 0;
while (true)
{
total += 100;
for (int i = 0; i < 100; i++)
{
if (Random.Range(0, 100) < 25) { mafia++; }
else { citizen++; }
}
int mafiaPerc = Mathf.FloorToInt(((float)mafia / (float)total) * 100f);
int citizenPerc = Mathf.FloorToInt(((float)citizen / (float)total) * 100f);
Debug.Log($"mafia : {mafiaPerc}%, citizen : {citizenPerc}%");
yield return new WaitForSeconds(0.5f);
}
}
You will see the printing lurking around 25% and 75%.
Answer by taoria123 · Jun 08, 2019 at 05:03 PM
One solution is that ...to make it easy ,just simply not to assign the random role to player but assign random player to role.
public GameObject[] Players;
string[] possibleRoles = {"Citizen" , "Mafia","something else"};
private float[] rolePercent = {0.25f,0.30f};
void Start()
{
Players = GameObject.FindGameObjectsWithTag ("Player");
AssignRole ();
}
void AssignRole()
{
//make an array to record the number of each role,
int[] roleNumber = new int[possibleRoles.Length];
//the last role is full at first.
roleNumber[possibleRoles.Length - 1] = Players.Length;
for (int roleId = 0; roleId < possibleRoles.Length-1; roleId++){
roleNumber[roleId] = Mathf.RoundToInt(Players.Length * rolePercent[roleId]);
//each time we calculate the number of a role,we minus the last role's number to fit the total player's number.
roleNumber[possibleRoles.Length - 1] -= roleNumber[roleId];
}
//to record current player array's random size.
int length = Players.Length;
for (int roleId = 0; roleId < possibleRoles.Length; roleId++){
for (int i = 0; i < roleNumber[roleId]; i++){
int randomPlayerIndex = UnityEngine.Random.Range (0, length);
Debug.Log("Player " + Players[randomPlayerIndex].name + " is named " + possibleRoles[roleId]);
//remove the player simply just make its value equals to last of the array
Players[randomPlayerIndex] = Players[--length];
}
}
}
It's mathematically work.Of course you can make the role assign to player as well,just record the number already given
once encounter the situation where the role you randomly picked is full.roll again .But these will cause a mathematically dead loop if you are very very very unlucky(:
to avoid this mathematical dilemma,you can just plus 1 to index you picked and this will cause some level of recursively check if you are very unlucky as well.
yet I think there must be a neat solution.But i don't know.
You have two loops and the second has a nested loop which means a lot slower and the logic is just not...simple. I am not trying to say my answer is the best possible but how this overly complicated solution would prevail over a 2 line answer that surely works?
Well since you can't really make sure the number of randomly generated role are exactly fit the requirement . It's not surely works in small case. for examlpe for 10 players ,you need 2 mafia and 8 citzens,but it maybe 1 and 9 or 3 and 7 and even worse as you say. you can't decide the number of each role by a random generator . It only works in large scale. And though my two nested loop looks not so effecient,but it's also a linear solution.Which would not be slow at all.
IEnumerator RandomCoroutine()
{
int mafia = 0; int citizen = 0; int total = 0;
int hit = 0;
while(true)
{
total += 4;
mafia = 0;
citizen = 0;
for (int i = 0; i < 4; i++)
{
if (Random.Range(0, 100) < 25) { mafia++; }
else { citizen++; }
}
if (mafia != 1 && citizen != 3){
hit++;
Debug.Log(((float)hit/total));
}
yield return new WaitForSeconds(0.01f);
}
}
And if there only 4 players ,you can see .the possibility the role assigned mismatch the requirement is near 15%.