ralgorithmrandomtidyverse

How do you code the creation of fixture lists for a sports league?


I'm trying to write a program that generates a fixture list for a sports league. If each team played each other home and away like in the English Premier League, this would be easy (expand_grid() or crossing() would be perfect), but this one is more complex.

I have a 17-team competition where each team plays 24 matches (12 at home and 12 away) for a total of 204 matches across the season. Each team will play 8 teams twice (home and away) and the other 8 teams only once (four at home and four away).

I cannot for the life of me work this out. All my attempts have basically started like this:

library(tidyverse)

# 17 team names
teams <- c(paste("Team", LETTERS[1:17]))

# Combinations of different teams
matches <- expand_grid(home = teams, away = teams) |>
  filter(home != away)

The issue now is that I don't know how to filter this down so each team will have only the 24 games. My focus on getting it to work for a given team obviously affects the number of matches the other team in the matchup is involved in. I don't know how to control this. I've tried sampling methods but this is giving me variability in how many games each team is left with.

Do any of you rstats geniuses out there know how to crack this?

Appreciate any help!


Solution

  • I would say, this problem seems "easy" but indeed not that trivial. It is highly similar to this question. Hope you can find some hints from there, too.


    One possible option might be interpreting the problem in the graph-theory manner, where vertices denote the teams, and incoming and outgoing arcs represent "Home" and "Away" matches, respectively. Note that, each team has 12 "Home" + 12 "Away" matches in total.

    Probably you can use sample_degseq to sample a graph with given in/out degree sequences, e.g.,

    library(igraph)
    
    matches <- sample_degseq(
        rep(12, length(teams)),
        rep(12, length(teams)),
        method = "simple.no.multiple"
    ) %>%
        set_vertex_attr(name = "name", value = teams[V(.)]) %>%
        as_data_frame() %>%
        setNames(c("home", "away"))
    

    which gives

    > matches
          home   away
    1   Team A Team D
    2   Team A Team E
    3   Team A Team F
    4   Team A Team G
    5   Team A Team H
    6   Team A Team I
    7   Team A Team J
    8   Team A Team L
    9   Team A Team M
    10  Team A Team O
    11  Team A Team P
    12  Team A Team Q
    13  Team B Team A
    14  Team B Team C
    15  Team B Team D
    16  Team B Team E
    17  Team B Team F
    18  Team B Team G
    19  Team B Team I
    20  Team B Team J
    21  Team B Team L
    22  Team B Team M
    23  Team B Team O
    24  Team B Team P
    25  Team C Team A
    26  Team C Team B
    27  Team C Team F
    28  Team C Team G
    29  Team C Team H
    30  Team C Team I
    31  Team C Team K
    32  Team C Team L
    33  Team C Team M
    34  Team C Team N
    35  Team C Team O
    36  Team C Team Q
    37  Team D Team B
    38  Team D Team E
    39  Team D Team G
    40  Team D Team H
    41  Team D Team I
    42  Team D Team J
    43  Team D Team K
    44  Team D Team L
    45  Team D Team M
    46  Team D Team N
    47  Team D Team P
    48  Team D Team Q
    49  Team E Team D
    50  Team E Team F
    51  Team E Team G
    52  Team E Team H
    53  Team E Team I
    54  Team E Team K
    55  Team E Team L
    56  Team E Team M
    57  Team E Team N
    58  Team E Team O
    59  Team E Team P
    60  Team E Team Q
    61  Team F Team A
    62  Team F Team B
    63  Team F Team C
    64  Team F Team D
    65  Team F Team E
    66  Team F Team H
    67  Team F Team I
    68  Team F Team J
    69  Team F Team K
    70  Team F Team L
    71  Team F Team P
    72  Team F Team Q
    73  Team G Team A
    74  Team G Team B
    75  Team G Team C
    76  Team G Team D
    77  Team G Team E
    78  Team G Team I
    79  Team G Team J
    80  Team G Team K
    81  Team G Team L
    82  Team G Team M
    83  Team G Team N
    84  Team G Team O
    85  Team H Team A
    86  Team H Team C
    87  Team H Team D
    88  Team H Team E
    89  Team H Team F
    90  Team H Team G
    91  Team H Team J
    92  Team H Team K
    93  Team H Team L
    94  Team H Team M
    95  Team H Team O
    96  Team H Team Q
    97  Team I Team A
    98  Team I Team B
    99  Team I Team E
    100 Team I Team F
    101 Team I Team H
    102 Team I Team K
    103 Team I Team L
    104 Team I Team M
    105 Team I Team N
    106 Team I Team O
    107 Team I Team P
    108 Team I Team Q
    109 Team J Team A
    110 Team J Team B
    111 Team J Team C
    112 Team J Team D
    113 Team J Team E
    114 Team J Team F
    115 Team J Team H
    116 Team J Team I
    117 Team J Team K
    118 Team J Team N
    119 Team J Team O
    120 Team J Team Q
    121 Team K Team A
    122 Team K Team B
    123 Team K Team C
    124 Team K Team D
    125 Team K Team E
    126 Team K Team G
    127 Team K Team H
    128 Team K Team I
    129 Team K Team J
    130 Team K Team M
    131 Team K Team N
    132 Team K Team P
    133 Team L Team A
    134 Team L Team B
    135 Team L Team C
    136 Team L Team D
    137 Team L Team H
    138 Team L Team I
    139 Team L Team J
    140 Team L Team M
    141 Team L Team N
    142 Team L Team O
    143 Team L Team P
    144 Team L Team Q
    145 Team M Team B
    146 Team M Team C
    147 Team M Team F
    148 Team M Team G
    149 Team M Team H
    150 Team M Team J
    151 Team M Team K
    152 Team M Team L
    153 Team M Team N
    154 Team M Team O
    155 Team M Team P
    156 Team M Team Q
    157 Team N Team A
    158 Team N Team B
    159 Team N Team C
    160 Team N Team D
    161 Team N Team E
    162 Team N Team F
    163 Team N Team G
    164 Team N Team H
    165 Team N Team K
    166 Team N Team L
    167 Team N Team M
    168 Team N Team P
    169 Team O Team A
    170 Team O Team B
    171 Team O Team C
    172 Team O Team E
    173 Team O Team F
    174 Team O Team G
    175 Team O Team H
    176 Team O Team J
    177 Team O Team M
    178 Team O Team N
    179 Team O Team P
    180 Team O Team Q
    181 Team P Team A
    182 Team P Team C
    183 Team P Team D
    184 Team P Team F
    185 Team P Team G
    186 Team P Team I
    187 Team P Team J
    188 Team P Team K
    189 Team P Team L
    190 Team P Team N
    191 Team P Team O
    192 Team P Team Q
    193 Team Q Team B
    194 Team Q Team C
    195 Team Q Team D
    196 Team Q Team E
    197 Team Q Team F
    198 Team Q Team G
    199 Team Q Team I
    200 Team Q Team J
    201 Team Q Team K
    202 Team Q Team N
    203 Team Q Team O
    204 Team Q Team P