JZonker
JZonker

Reputation: 81

How can I create a random event that will not repeat results?

I am trying to make a team generating application using Xcode and C++ that will generate either teams of three or teams of four. Currently, I am able to input names and randomly generate the teams using arrays:

    for (j=1;j < count; j++) {

    int index=rand() % count;


    NSString *temp = Array[j];
    Array[j]=Array[index];
    Array[index]=temp;

From this array, I am assigning teams of three based on the order of the array. So Array [1], [2], and [3] make up team #1. Array [4], [5], and [6] make up team #2, and so fourth.

From here, I would like to randomly generate new teams using the same name pool as before, but not having people put in teams with people that they were already in a team with.

For example, if person #1, #2, and #3 were all placed in the same team, the next time I generate teams, person #1, #2, and #3 would all be on separate teams.

This is my main focus for now. Eventually, I would like to be able to make the program adjust to allow for repeat team members as non-repeat team members becomes impossible on later team generations.

Upvotes: 2

Views: 707

Answers (3)

Pierre-Antoine Guillaume
Pierre-Antoine Guillaume

Reputation: 1126

I'm not sure I got it right about the teams of 4 or teams of 3, but, to avoid mathematical complexity (checking more and more exponential possibilities); I suggest that you generate each possible team and pick the teams at random instead of trying to generates them random and take them in order.

I miss a part of the algorithm, so I will put a simplified version here, for teams of 3 players.

typedef std::tuple<Player,Player,Player> team;
std::vector<Team> definitive_teams, list_of_teams;

//that's the part where I miss the algorithm,
//where you create EACH possible team
//and store them
list_of_teams.reserve(Number_of_team_max); //you have to figure that too
list_of_teams.push_back(make_tuple(arg1,arg2,arg3));
//then simply :

definitive_teams.resize(list_of_teams.size());

size_t index;
std::srand(std::time(0));
for (size_t i {0};i < definitive_teams.size();++i)
{
    index= std::rand()%(list_of_teams.size() - i);
    definitive_teams[i] = list_of_teams[index];
    if (index != list_of_teams.size() - i)
        swap(list_of_teams[index],list_of_teams[list_of_teams.size() - i]);
}

And then you have your whole thing.

Sorry for the partial solution.

Upvotes: 1

MSalters
MSalters

Reputation: 179981

This looks like a clear case for backtracking. Not sure if it's the most efficient approach, but it's simple and certainly better than randomized algorithms.

The first datastructure needed is an array of team members who've been in the same team. For N people, that's a (NN-1)/2 set of bools. It is probably easier to use a full NN array. std::vector<std::vector<bool>> conflicts

The second datastructure is simply an array of bools std::vector<bool> assigned, indicating which people have already been assigned to a team in the current round.

The third datastructures is the actual team assignment, keyed by both person and team. Behind the scenes, this is best implemented by two arrays, one where the person number is the index and one where the team number is the index.

The algorithm works as follows

In each round:
  Set all teams to empty
  Find first non-assigned person in `assigned`
    Add person to first team that has <4 members and no conflicts.
    If not team found, backtrack:
      Undo the assignment of the _previous_ person
      Assign person to the next possible team
    When team found: 
       Update `assigned`
       Update team membership
  Until all people assigned to teams
  Update `conflicts` with team membership from this round
Continue with next round

Upvotes: 2

Adam
Adam

Reputation: 952

You need to be careful here. There are some cases where you can't generate teams with those rules. For example, if you're splitting 6 people into two teams of 3 then the second set of teams wouldn't be possible to generate.

You can also get into a partially placed state where there is no solution that just involves adding players to teams. This means you can't just pick at random and reject placement into a team which contains a member you were with before.

I think the simplest solution is shuffling the whole state until it's correct.

To do that you can just shuffle the array with std::random_shuffle() until you find a valid configuration. Note that this will search forever if there is no valid solution, and could take a long time if only a very small proportion of the configurations are actually valid.

There's also std::next_permutation() if you want to iterate through every possibility. However, unless the number of team members is low there will be a very large number of possible configurations. You can cut down the number of combinations somewhat, because the players within a team can be in any order.

Upvotes: 1

Related Questions