JavaScript tournament scheduling (fixture generation) algorithm
I have 10 teams to match up. Each team will play 9 matches in a fixture such that all teams play with a separate competition at every round.


Let's build a schedule for 10 teams. I intuitively came up with the following circulant 10x10 matrix A with entry A[i, j] denoting the opponent of team i in round j:



Each row represents the schedule for a single team. We note that for each round j teams are partitioned into pairs playing against each other - i.e. A[A[i, j], j] = i.

However, there is a flaw: According to above schedule, there is a round j for each team where it has to play against itself (the red squares) - i.e. A[i, j] = i.

That's because a correct schedule for 10 teams can only have 9 rounds, not 10. To fix this, we first slice the main diagonal of A - all matches against team 9 - and end up with:



Now, we re-introduce the matches against team 9 wherever a team would have to play against itself (the red squares). We also have to fix the opponents of team 9 to reflect these changes. This practically means that for each round j we swap A[9, j] with A[i, j] where i denotes the self-matched team (the red square):



This is the resulting correct schedule with all swapped matches highlighted in red. This schedule is identical to the one you compute and pretty simple to generate:


Create a circulant 10 x 9 matrix where each row is a circular shift of [0,1,2,3,4,5,6,7,8].
For each round or column, replace the self-match with a match against team 9 and let team 9 play against the self-matched team.


While there are exactly 945 different ways to partition 10 teams into pairs and thus many more ways to generate a correct schedule, I could not come up with a simpler or more intuitive schedule.


  While it works fine i would like to know if my calculations could be
  simplified any further.


I think that by closely following the above recipe, you can avoid the more obscure arithmetic and come up with a simpler and more intuitive 'generative' algorithm. The scheduling is encapsulated in the round(n, j) function:



// Schedule single round `j` for 'n' teams:
function round(n, j) {
  let m = n - 1;
  let round = Array.from({length: n}, (_, i) =&gt; (m + j - i) % m); // circular shift
  round[round[m] = j * (n &gt;&gt; 1) % m] = m; // swapping self-match
  return round;
}

// Schedule matches of 'n' teams:
function fixture(n) {
  let rounds = Array.from({length: n - 1}, (_, j) =&gt; round(n, j));
  return Array.from({length: n}, (_, i) =&gt; ({
    id: "Team_" + i,
    matches: rounds.map(round =&gt; "Team_" + round[i])
  }));
}

// Example:
console.log(fixture(10));