Round-robin scheduling algorithm for Premier League style football tournament in VB.NET

92 Views Asked by At

I am creating a basic, quite bare-bones Football Manager game in VB.NET. The game runs on a console window. I have already set up all the foundations and now I need to schedule the 20 clubs in the tournament to play each other once and away for a total of 38 matches per club, randomly. However, I cannot for the life of me get it right. I've spent three days working on the scheduling algorithm, and am wondering if someone can help me out.

The algorithm should do this:

  • There will be 38 rounds
  • There will be 10 matches per round
  • Each club plays once per round, either at home or away.
  • Each club will play a total of 19 home games and 19 away games to add up to 38. Clubs must play each other club only once at home and once away.

This is what I have done so far, which is wrong and failed to achieve my objectives:

  Sub CreateFixtures()
    Randomize()
    Dim totalRounds = (ClubList.Count - 1) 
    Dim matchID As Integer = 0
    Dim rnd As New Random()

    For round = 1 To 38
        Debug.WriteLine($"Round {round}")
        Dim availableTeams = New List(Of ClubClass)(ClubList)

        While availableTeams.Count > 1 ' Ensure there are at least 2 teams left
            Dim homeTeamIndex = rnd.Next(0, availableTeams.Count)
            Dim homeTeam = availableTeams(homeTeamIndex)

            ' Remove homeTeam from available teams to prevent it from playing against itself
            availableTeams.RemoveAt(homeTeamIndex)

            ' Select a random away team that hasn't already played against the home team
            Dim availableAwayTeams = availableTeams.Where(Function(team) Not homeTeam.HasPlayedAgainst(team)).ToList()

            If availableAwayTeams.Count > 0 Then
                Dim awayTeamIndex = rnd.Next(0, availableAwayTeams.Count)
                Dim awayTeam = availableAwayTeams(awayTeamIndex)

                CreateMatch(matchID, homeTeam, awayTeam, round)
                availableTeams.Remove(awayTeam)
                Debug.WriteLine($"{homeTeam.name} vs {awayTeam.name}")
                matchID += 1
            End If
        End While
    Next
End Sub
1

There are 1 best solutions below

0
VonC On

Your algorithm seems to fall short in systematically making sure every team plays with each other exactly once at home and once away across the entire season.

From "Round-robin tournament", you could try a "circle method" for round-robin scheduling: the idea is to fix one team (usually the first one) and rotate the others around it.

Round 1          Round 2          Round 3         ...
1 vs 20          1 vs 19          1 vs 18         ...
2 vs 19          20 vs 18         19 vs 17        ...
3 vs 18          2 vs 17          20 vs 16        ...
...                                               ...
19 vs 2          4 vs 20          3 vs 19         ...
20 vs 1          3 vs 2           2 vs 20         ...

That would be a way to make sure each team plays every other team exactly once in the first half of the season. Then, you would repeat the process for the second half of the season, switching home and away teams.

Sub CreateFixtures(clubs As List(Of String))
    Dim totalClubs As Integer = clubs.Count
    Dim totalRounds As Integer = (totalClubs - 1) * 2 ' Each team plays 38 rounds
    Dim matchesPerRound As Integer = totalClubs / 2

    ' Generate the first half of the season
    For round As Integer = 1 To totalClubs - 1
        Debug.WriteLine($"Round {round}")
        For match As Integer = 0 To matchesPerRound - 1
            Dim homeTeamIndex As Integer = (round + match) Mod (totalClubs - 1)
            Dim awayTeamIndex As Integer = (totalClubs - 1 - match + round) Mod (totalClubs - 1)

            ' Adjust indices to skip the fixed team
            If match = 0 Then
                awayTeamIndex = totalClubs - 1
            End If

            Dim homeTeam As String = clubs(homeTeamIndex)
            Dim awayTeam As String = clubs(awayTeamIndex)

            Debug.WriteLine($"{homeTeam} vs {awayTeam}")
        Next
    Next

    ' Repeat the process for the second half of the season, switching home and away
    For round As Integer = totalClubs To totalRounds - 1
        Debug.WriteLine($"Round {round}")
        For match As Integer = 0 To matchesPerRound - 1
            Dim homeTeamIndex As Integer = (round + match) Mod (totalClubs - 1)
            Dim awayTeamIndex As Integer = (totalClubs - 1 - match + round) Mod (totalClubs - 1)

            ' Adjust indices to skip the fixed team
            If match = 0 Then
                homeTeamIndex = totalClubs - 1
            End If

            Dim homeTeam As String = clubs(awayTeamIndex) ' Switch home and away
            Dim awayTeam As String = clubs(homeTeamIndex)

            Debug.WriteLine($"{homeTeam} vs {awayTeam}")
        Next
    Next
End Sub

You would call CreateFixtures with a list of club names.