This should be easy enough using modular arithmetic:
UPDATE 2: (as the correct algorithm promised)
public void ListMatches(List<string> ListTeam) { if (ListTeam.Count % 2 != 0) { ListTeam.Add("Bye"); } int numDays = (numTeams - 1); int halfSize = numTeams / 2; List<string> teams = new List<string>(); teams.AddRange(ListTeam.Skip(halfSize).Take(halfSize)); teams.AddRange(ListTeam.Skip(1).Take(halfSize -1).ToArray().Reverse()); int teamsSize = teams.Count; for (int day = 0; day < numDays; day++) { Console.WriteLine("Day {0}", (day + 1)); int teamIdx = day % teamsSize; Console.WriteLine("{0} vs {1}", teams[teamIdx], ListTeam[0]); for (int idx = 1; idx < halfSize; idx++) { int firstTeam = (day + idx) % teamsSize; int secondTeam = (day + teamsSize - idx) % teamsSize; Console.WriteLine("{0} vs {1}", teams[firstTeam], teams[secondTeam]); } } }
which will print matches of each team.
Let me quickly try to explain how the algorithm works:
I noticed that since we rotate all the commands except the first, if we put all the commands in the array except the first, then we just need to read the first command from this array using the index based offset on a daily basis and do modular arithmetic to properly wrap . In practice, we will consider this array as endlessly repeating in both directions, and we will gradually bring our gaze to the right (or left).
However, there is one catch, and this is the fact that we need to arrange the teams in a very specific way so that it works correctly. Otherwise, we will not get the correct rotation. Because of this, we also need to read the corresponding second command in a very strange way.
The correct way to prepare your list is as follows:
- Never put the first team (Team # 1) on the list.
- Take the last half of the list of commands and put them at the top of the list.
- Take the first half of the list, cancel it and put it on the list (but not in Team # 1).
Now the correct way to read the list is as follows:
- For each day, increase the first index you look at
1 . - For the first team that you see in this place, map this team to Team # 1.
- For the next team in the list (
(day + idx) % numDays ) we usually compare it with a team that is compensated by half the number of teams minus 1 (minus 1 because we were dealing with the first match). However, since the second half of our list was prepared by return, we must match this offset in the returned second half of the list. An easier way is to notice that this is equivalent to matching the same index, but from the end of the list. Given the current day offset, which is (day + (numDays - idx)) % numDays .
UPDATE 3: I was not happy that my decision included such a collapsed selection, matching, reversing array elements. After I thought about my decision, I realized that I was too hanged to maintain the order of the teams. However, this is not a mandatory requirement, and you can get another, but equally valid schedule, without worrying about the initial order. All that matters is the selection algorithm, which I describe in the second part of my explanation.
This way you can simplify the following lines:
teams.AddRange(ListTeam.Skip(halfSize).Take(halfSize)); teams.AddRange(ListTeam.Skip(1).Take(halfSize -1).ToArray().Reverse());
in
teams.AddRange(ListTeam);