algorithmcombinationscombinatoricsschedulesports-league-scheduling-problem

Scheduling a 16-team 1v1 competition with 6 different game types


I've been given the task of creating the schedule for a company's team competition. Initially I thought this would be pretty trivial, but I'm having some trouble coming up with a valid solution. Here are the facts that need to be met:

This isn't a round robin since all teams will not play each other. It's kind of similar to a Swiss Tournament, but with the constraint of having multiple game types that all teams must play. I'm struggling to figure out the correct algorithm to determine this schedule and any help or information leading to a solution would be great.


Solution

  • I think that you could use local search for this, but let me give you a mathematical construction.

    Divide the 16 teams into 8 A teams and 8 B teams. Each A team will play all but 2 B teams. Each B team will play all but 2 A teams.

    This construction requires two mutually orthogonal 8x8 Latin squares, e.g.,

    abcdehfg
    badchegf
    cdabgfhe
    dcbafgeh
    ehgfabdc
    hefgbacd
    fghedcab
    gfehcdba
    
    abcdefgh
    cdabhgfe
    efhgabdc
    hgefcdba
    dcbaghef
    badcfehg
    feghbacd
    ghfedcab
    

    Index the rows by A teams and the columns by B teams. The entries of the first Latin square specify the activity in which an A team will compete against a B team. Two of the letters are treated as rest. By the properties of Latin squares, each team completes each activity exactly once (and rests twice).

    The entries of the second Latin square indicate when an A team competes against a B team (or both rest). By the properties of Latin squares, each team does one thing in each round. By the properties of mutually orthogonal Latin squares, each activity occurs exactly once in each round.

    In Python 3:

    import string
    
    
    def latin8a(i, j):
        return i ^ j
    
    
    def latin8b(i, j):
        b = i >> 2
        return (i << 1) ^ (b << 3 | b << 1 | b) ^ j
    
    
    a_teams = string.ascii_uppercase[:8]
    b_teams = string.ascii_uppercase[8:16]
    for i in range(8):
        print()
        print('Round', i + 1)
        for j in range(6):
            print(a_teams[latin8a(i, j)], 'vs', b_teams[latin8b(i, j)],
                  'in game type', string.ascii_lowercase[j])
    

    Output:

    Round 1
    A vs I in game type a
    B vs J in game type b
    C vs K in game type c
    D vs L in game type d
    E vs M in game type e
    F vs N in game type f
    
    Round 2
    B vs K in game type a
    A vs L in game type b
    D vs I in game type c
    C vs J in game type d
    F vs O in game type e
    E vs P in game type f
    
    Round 3
    C vs M in game type a
    D vs N in game type b
    A vs O in game type c
    B vs P in game type d
    G vs I in game type e
    H vs J in game type f
    
    Round 4
    D vs O in game type a
    C vs P in game type b
    B vs M in game type c
    A vs N in game type d
    H vs K in game type e
    G vs L in game type f
    
    Round 5
    E vs L in game type a
    F vs K in game type b
    G vs J in game type c
    H vs I in game type d
    A vs P in game type e
    B vs O in game type f
    
    Round 6
    F vs J in game type a
    E vs I in game type b
    H vs L in game type c
    G vs K in game type d
    B vs N in game type e
    A vs M in game type f
    
    Round 7
    G vs P in game type a
    H vs O in game type b
    E vs N in game type c
    F vs M in game type d
    C vs L in game type e
    D vs K in game type f
    
    Round 8
    H vs N in game type a
    G vs M in game type b
    F vs P in game type c
    E vs O in game type d
    D vs J in game type e
    C vs I in game type f