Sub SchemaCompetitie()
Dim AantPloegen As Integer, AantMatchenPerWeekPerPloeg As Integer, AantKerenTegenMekaar As Integer
Dim AantMatchen As Integer, AantMatchenPerWeek As Integer, weeknr As Integer
Dim TeamSpeler As String, r As Integer, i As Integer, c As Range
Application.ScreenUpdating = False
MsgBox "Er worden eerst wat gegevens opgevraagd." & vbCr & vbCr & "Vul die correct in en dan wordt de kalender gegenereerd."
TeamSpeler = Application.InputBox("Gaat het om teams of spelers?" & vbCr & vbCr & "Typ het woord team of speler in." _
, "Vraag 1 van 4", "team", , , , 2)
TeamSpeler = LCase(TeamSpeler)
AantPloegen = Application.InputBox("Wat is het aantal " & TeamSpeler & "s? (Moet een even aantal zijn)", _
"Vraag 2 van 4", 14, , , , 1)
AantMatchenPerWeekPerPloeg = Application.InputBox("Hoeveel matchen speelt elk" & IIf(TeamSpeler = "team", " ", "e ") & _
TeamSpeler & " per week?", "Vraag 3 van 4", 2, , , , 1)
AantKerenTegenMekaar = Application.InputBox("Hoeveel keer spelen de " & TeamSpeler & "s tegen mekaar?", _
"Vraag 4 van 4", 2, , , , 1)
AantMatchen = AantPloegen * (AantPloegen - 1) * AantKerenTegenMekaar / 2
AantMatchenPerWeek = AantMatchenPerWeekPerPloeg * AantPloegen / 2
With Range("A1")
.CurrentRegion.ClearContents
.Offset(, 0) = "Match"
.Offset(, 1) = "Week"
.Offset(, 2) = "Match per week"
.Offset(, 3) = "Thuis"
.Offset(, 4) = "Uit"
.Resize(, 5).Font.Bold = True
For r = 1 To AantMatchen
weeknr = Int((r - 0.1) / (AantMatchenPerWeek / 2)) + 1
.Offset(r, 0) = r
.Offset(r, 1) = weeknr
.Offset(r, 2) = IIf(weeknr / 2 - Int(weeknr / 2) = 0.5, 1, 2)
Next
ScheduleManager (AantPloegen)
.Offset(1, 3).Resize(AantMatchen / 2).Copy .Offset(AantMatchen / 2 + 1, 4)
.Offset(1, 4).Resize(AantMatchen / 2).Copy .Offset(AantMatchen / 2 + 1, 3)
For Each c In .Offset(1, 3).Resize(AantMatchen, 2)
c = TeamSpeler & " " & c
Next
.Resize(, 5).EntireColumn.AutoFit
.Offset(, 5).Resize(, 4).EntireColumn.ClearContents
.Select
End With
Application.ScreenUpdating = True
End Sub
Sub initializeSystem(ByRef TeamMap() As Byte, ByRef AvailTeams() As Byte)
Dim i As Integer, j As Integer
For i = 1 To UBound(TeamMap, 1)
For j = i + 1 To UBound(TeamMap, 1)
TeamMap(i, j) = 1
Next j
Next i
For i = 1 To UBound(AvailTeams)
AvailTeams(i) = 1
Next i
End Sub
Function FirstAvailCompetitor(TeamMap() As Byte, ByVal CurrTeam As Integer, AvailTeams() As Byte, _
ByVal StartAfter As Integer) As Integer
Dim i As Integer
If StartAfter = 0 Then StartAfter = CurrTeam
For i = StartAfter + 1 To UBound(TeamMap, 2)
If AvailTeams(i) And TeamMap(CurrTeam, i) = 1 Then
FirstAvailCompetitor = i
Exit Function
End If
Next i
End Function
Function FindRandomCompetitor(ByRef TeamMap() As Byte, CurrTeam As Integer, AvailTeams() As Byte) As Integer
Dim i As Integer, StartAt As Integer
StartAt = Fix(Rnd() * (UBound(TeamMap, 1) - CurrTeam)) + CurrTeam + 1
i = StartAt
Do
If AvailTeams(i) And TeamMap(CurrTeam, i) = 1 Then
FindRandomCompetitor = i
Exit Function
End If
If i = UBound(TeamMap, 2) Then
i = CurrTeam + 1
Else: i = i + 1
End If
Loop Until i = StartAt
End Function
Function FindCompetitor(ByRef TeamMap() As Byte, CurrTeam As Integer, AvailTeams() As Byte, StartAfter As Integer) As Integer
Dim i As Integer, StartAt As Integer
If StartAfter = 0 Then
FindCompetitor = FindRandomCompetitor(TeamMap, CurrTeam, AvailTeams)
Else
FindCompetitor = FirstAvailCompetitor(TeamMap, CurrTeam, AvailTeams)
End If
End Function
Function FirstAvailTeam(ByRef AvailTeams() As Byte) As Integer
Dim i As Integer
For i = 1 To UBound(AvailTeams)
If AvailTeams(i) = 1 Then
FirstAvailTeam = i
Exit Function
End If
Next i
End Function
Function schedAPair(ByVal nbrTeams As Integer, ByRef TeamMap() As Byte, AvailTeams() As Byte, RecursionDepth As Integer, _
ByRef RsltMap() As Integer) As Boolean
Dim T1 As Integer, T2 As Integer, Done As Boolean, Success As Boolean, FailureCount As Integer
T1 = FirstAvailTeam(AvailTeams)
If T1 = 0 Then 'all teams assigned
schedAPair = True
Exit Function
End If
T2 = FindRandomCompetitor(TeamMap, T1, AvailTeams)
Do
If T2 = 0 Then 'infeasible solution
Done = True
Else
AvailTeams(T1) = 0: AvailTeams(T2) = 0
RsltMap(RecursionDepth, 1) = T1
RsltMap(RecursionDepth, 2) = T2
Success = schedAPair(nbrTeams, TeamMap, AvailTeams, RecursionDepth + 1, RsltMap)
If Not Success Then 'Infeasible solution downstream
FailureCount = FailureCount + 1
AvailTeams(T1) = 1: AvailTeams(T2) = 1
RsltMap(RecursionDepth, 1) = 0
RsltMap(RecursionDepth, 2) = 0
T2 = FirstAvailCompetitor(TeamMap, T1, _
AvailTeams, IIf(FailureCount = 1, 0, T2))
End If
Done = Success
End If
Loop Until Done
schedAPair = Success
End Function
Sub printRslt(RsltMap() As Integer)
Dim dest As Range, i As Integer
Set dest = Cells(Cells.Rows.Count, 4).End(xlUp).Offset(1)
For i = 1 To UBound(RsltMap, 1)
dest.Offset(i - 1, 0).Value = RsltMap(i, 1)
dest.Offset(i - 1, 1).Value = RsltMap(i, 2)
Next i
End Sub
Sub updateSystem(ByRef TeamMap() As Byte, ByRef RsltMap() As Integer, ByRef AvailTeams() As Byte)
Dim i As Integer
For i = 1 To UBound(RsltMap, 1)
TeamMap(RsltMap(i, 1), RsltMap(i, 2)) = 0
RsltMap(i, 1) = 0: RsltMap(i, 2) = 0
Next i
For i = 1 To UBound(AvailTeams)
AvailTeams(i) = 1
Next i
End Sub
Sub ScheduleManager(ploegen As Integer)
Dim nbrTeams As Integer, SchedRslt As Boolean
nbrTeams = ploegen
If nbrTeams Mod 2 = 1 Then
MsgBox "Please enter an even number (2, 4, 6, etc.)"
Exit Sub
End If
ReDim TeamMap(1 To nbrTeams, 1 To nbrTeams) As Byte, RsltMap(1 To nbrTeams / 2, 1 To 2) As Integer, AvailTeams(1 To nbrTeams) As Byte
'actually need only upper triangle matrix
'(above the main diagonal)
initializeSystem TeamMap, AvailTeams
'Establishes all valid combinations
Do
SchedRslt = schedAPair(nbrTeams, TeamMap, AvailTeams, 1, RsltMap)
If SchedRslt Then
printRslt RsltMap()
updateSystem TeamMap, RsltMap, AvailTeams
End If
Loop While SchedRslt
End Sub