skip to Main Content

I’m trying to create a UEFA Champions League 24 ‘Swiss Model’ competition featuring 36 teams. Each team will compete against 8 unique opponents, resulting in a total of 144 matches. I have already created a list of matchups. Is there a way to sort every matchup so that each team can have an equal number (4 in this case) of home and away games? The first position in a matchup indicates the home team, while the second position indicates the away team.

I have attempted to check if the total number of home games for the first team exceeds 4 matches (since there are 8 rounds). If it does, it becomes the away team. However, the results are still not equally distributed.

JSFiddle example

const matchups = [
    [
        "35",
        "36"
    ],
    [
        "36",
        "34"
    ],
    [
        "12",
        "36"
    ],
    [
        "36",
        "28"
    ],
    [
        "36",
        "3"
    ],
    [
        "36",
        "19"
    ],
    [
        "36",
        "16"
    ],
    [
        "36",
        "14"
    ],
    [
        "13",
        "20"
    ],
    [
        "12",
        "13"
    ],
    [
        "13",
        "27"
    ],
    [
        "7",
        "13"
    ],
    [
        "1",
        "13"
    ],
    [
        "21",
        "13"
    ],
    [
        "35",
        "13"
    ],
    [
        "13",
        "15"
    ],
    [
        "37",
        "3"
    ],
    [
        "21",
        "37"
    ],
    [
        "54",
        "37"
    ],
    [
        "11",
        "37"
    ],
    [
        "37",
        "27"
    ],
    [
        "1",
        "37"
    ],
    [
        "37",
        "14"
    ],
    [
        "22",
        "37"
    ],
    [
        "15",
        "17"
    ],
    [
        "11",
        "15"
    ],
    [
        "15",
        "27"
    ],
    [
        "1",
        "15"
    ],
    [
        "15",
        "54"
    ],
    [
        "41",
        "15"
    ],
    [
        "40",
        "15"
    ],
    [
        "23",
        "1"
    ],
    [
        "40",
        "23"
    ],
    [
        "25",
        "23"
    ],
    [
        "24",
        "23"
    ],
    [
        "41",
        "23"
    ],
    [
        "23",
        "3"
    ],
    [
        "23",
        "9"
    ],
    [
        "18",
        "23"
    ],
    [
        "41",
        "27"
    ],
    [
        "27",
        "54"
    ],
    [
        "40",
        "27"
    ],
    [
        "27",
        "18"
    ],
    [
        "27",
        "19"
    ],
    [
        "7",
        "3"
    ],
    [
        "33",
        "3"
    ],
    [
        "32",
        "3"
    ],
    [
        "2",
        "3"
    ],
    [
        "3",
        "54"
    ],
    [
        "41",
        "29"
    ],
    [
        "40",
        "29"
    ],
    [
        "29",
        "28"
    ],
    [
        "2",
        "29"
    ],
    [
        "10",
        "29"
    ],
    [
        "26",
        "29"
    ],
    [
        "12",
        "29"
    ],
    [
        "29",
        "22"
    ],
    [
        "25",
        "34"
    ],
    [
        "34",
        "24"
    ],
    [
        "10",
        "34"
    ],
    [
        "34",
        "16"
    ],
    [
        "11",
        "34"
    ],
    [
        "48",
        "34"
    ],
    [
        "34",
        "17"
    ],
    [
        "14",
        "24"
    ],
    [
        "14",
        "9"
    ],
    [
        "33",
        "14"
    ],
    [
        "25",
        "14"
    ],
    [
        "7",
        "14"
    ],
    [
        "14",
        "17"
    ],
    [
        "21",
        "17"
    ],
    [
        "48",
        "17"
    ],
    [
        "32",
        "17"
    ],
    [
        "17",
        "16"
    ],
    [
        "12",
        "17"
    ],
    [
        "28",
        "1"
    ],
    [
        "28",
        "25"
    ],
    [
        "28",
        "21"
    ],
    [
        "28",
        "43"
    ],
    [
        "11",
        "28"
    ],
    [
        "28",
        "9"
    ],
    [
        "54",
        "12"
    ],
    [
        "54",
        "33"
    ],
    [
        "54",
        "43"
    ],
    [
        "54",
        "25"
    ],
    [
        "16",
        "25"
    ],
    [
        "16",
        "33"
    ],
    [
        "16",
        "43"
    ],
    [
        "7",
        "16"
    ],
    [
        "16",
        "18"
    ],
    [
        "19",
        "24"
    ],
    [
        "19",
        "12"
    ],
    [
        "19",
        "48"
    ],
    [
        "11",
        "19"
    ],
    [
        "10",
        "19"
    ],
    [
        "19",
        "1"
    ],
    [
        "2",
        "43"
    ],
    [
        "43",
        "18"
    ],
    [
        "40",
        "43"
    ],
    [
        "7",
        "43"
    ],
    [
        "32",
        "43"
    ],
    [
        "18",
        "48"
    ],
    [
        "18",
        "10"
    ],
    [
        "18",
        "2"
    ],
    [
        "18",
        "20"
    ],
    [
        "25",
        "7"
    ],
    [
        "26",
        "25"
    ],
    [
        "32",
        "9"
    ],
    [
        "9",
        "48"
    ],
    [
        "9",
        "22"
    ],
    [
        "9",
        "2"
    ],
    [
        "9",
        "10"
    ],
    [
        "41",
        "20"
    ],
    [
        "20",
        "22"
    ],
    [
        "20",
        "21"
    ],
    [
        "20",
        "10"
    ],
    [
        "20",
        "40"
    ],
    [
        "20",
        "32"
    ],
    [
        "10",
        "41"
    ],
    [
        "35",
        "10"
    ],
    [
        "22",
        "33"
    ],
    [
        "22",
        "7"
    ],
    [
        "35",
        "22"
    ],
    [
        "22",
        "32"
    ],
    [
        "48",
        "35"
    ],
    [
        "48",
        "40"
    ],
    [
        "48",
        "41"
    ],
    [
        "24",
        "41"
    ],
    [
        "24",
        "2"
    ],
    [
        "24",
        "21"
    ],
    [
        "24",
        "12"
    ],
    [
        "33",
        "32"
    ],
    [
        "33",
        "11"
    ],
    [
        "33",
        "35"
    ],
    [
        "26",
        "32"
    ],
    [
        "21",
        "7"
    ],
    [
        "26",
        "21"
    ],
    [
        "1",
        "26"
    ],
    [
        "1",
        "35"
    ],
    [
        "2",
        "40"
    ],
    [
        "2",
        "26"
    ],
    [
        "35",
        "26"
    ],
    [
        "26",
        "11"
    ],
    [
        "12",
        "11"
    ]
]

const totalRounds = 8;

matchups.forEach((matchup) => {
  matchup.sort((homeTeam, awayTeam) => {
      const homeMatch = matchups.filter((m) => m[0] === homeTeam);
      return homeMatch.length > (totalRounds / 2 ) ? 1 : -1;
  });
});

const home = _.groupBy(matchups, m=> m[0])
const away = _.groupBy(matchups, m=> m[1])

console.log("home", home)
console.log("away", away)
console.log("combined",_.mergeWith(home,away, ((objValue,srcValue)=>{
   if(Array.isArray(objValue)){
     return objValue.concat(srcValue);
   }
})))

2

Answers


  1. Here’s an example for a 5-team pool:

    Consider a Home/away match table for teams from A to E:

    homeaway A B C D E
    A O O X X
    B X O O X
    C X X O O
    D O X X O
    E O O X X

    which means for instance that Team A plays home versus Team B and C, and away versus Team D and E.

    I have arbitrary filled the home/away match matrix, but it is consistent with your rule: 2 home games and 2 away games for each team (in this 5-team pool example).

    Now, if you add some randomness between your array of [Team 1, Team 2, ...] and the array of [Team A, Team B, ...], you would end up with a randomized championship, with the appropriate amount of home games and away games.

    I can add more details if this is not crystal clear.

    EDIT:

    I am unsure if all 9 teams of each pool must play with each other only once, or if each team of the 36 listed must play against 8 random opponents, avoiding any second encounter.

    Login or Signup to reply.
  2. Solve this via max-flow-min-cut.

    Create the network like this:

    Nodes: Source, Sink, 1 per team, 1 per match.

    Arcs:

    • source -> team_i, capacity 4, for each team.
    • team_i -> match_j, capacity 1, for each of the 8 matches that include team_i.
    • match_j -> sink, capacity 1, for each match.

    Now, find the max flow through this network using max-flow-min-cut. Since all capacities are integers, we can find an integer solution (where all flows are integers). Interpret a flow from a team to a match as saying that team is playing at home in that match.

    If a solution exists, it corresponds to a max flow of 144, 1 per match, and the max-flow-min-cut algorithm will find it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search