Option Explicit
Dim wsNames As Worksheet, wsCapacity As Worksheet
Dim rName As Range, rCapacity As Range
Sub PlaceStudents()
Dim iName As Long, iCapacity As Long, i As Long, iChoice As Long, iLimit As Long
Dim sName As String, sActivity As String
Dim collLimit As Collection
'init
Set wsNames = Worksheets("Names")
wsNames.Cells(1, 1).CurrentRegion.Interior.ColorIndex = xlColorIndexNone
Set wsCapacity = Worksheets("Capacity")
Set rCapacity = wsCapacity.Cells(1, 1).CurrentRegion
ReDim aLimit(1 To rCapacity.Rows.Count)
'make working copy
Call pvtDeleteSheet("Working Names")
wsNames.Copy after:=wsNames
ActiveSheet.Name = "Working Names"
Set wsNames = Worksheets("Working Names")
'stack activities
With wsNames
'names
Set rName = Range(.Cells(2, 1), .Cells(2, 1).End(xlDown))
rName.Copy .Cells(2, 1).End(xlDown).Offset(1, 0)
rName.Copy .Cells(2, 1).End(xlDown).Offset(1, 0)
'names and activty 3
Range(.Cells(2, 3), .Cells(2, 3).End(xlDown)).Copy .Cells(2, 2).End(xlDown).Offset(1, 0)
Range(.Cells(2, 4), .Cells(2, 4).End(xlDown)).Copy .Cells(2, 2).End(xlDown).Offset(1, 0)
.Columns(4).ClearContents
.Columns(3).ClearContents
.Cells(1, 3).Value = "Assigned"
End With
'add sheets
With wsCapacity
For iCapacity = 2 To .Cells(1, 1).CurrentRegion.Rows.Count
'some have more than one
For i = 1 To pvtSites(.Cells(iCapacity, 1).Value)
If pvtSites(.Cells(iCapacity, 1).Value) = 1 Then
sActivity = .Cells(iCapacity, 1).Value
Else
sActivity = .Cells(iCapacity, 1).Value & " " & i
End If
'delete if exists
Call pvtDeleteSheet(sActivity)
Worksheets.Add after:=Worksheets(Worksheets.Count)
ActiveSheet.Name = sActivity
ActiveSheet.Cells(1, 1).Value = "Name"
Next i
Next iCapacity
End With
'fill limit collection
Set collLimit = New Collection
For iChoice = 2 To wsCapacity.Cells(1, 1).CurrentRegion.Rows.Count
sActivity = wsCapacity.Cells(iChoice, 1).Value
collLimit.Add pvtCapacity(sActivity) * pvtSites(sActivity), sActivity
Next iChoice
With wsNames
'assign names to activity
For iName = 2 To .Cells(1, 1).CurrentRegion.Rows.Count
sName = .Cells(iName, 1).Value
sActivity = .Cells(iName, 2).Value
'blank = no more openings or already has activity
If Len(sActivity) = 0 Then GoTo NextName
'assign
iLimit = collLimit(sActivity)
.Cells(iName, 3).Value = iLimit
collLimit.Remove sActivity
collLimit.Add iLimit - 1, sActivity
'assigned, so clear remaining requests
For i = iName + 1 To .Cells(1, 1).CurrentRegion.Rows.Count
If .Cells(i, 1).Value = sName Then .Cells(i, 2).ClearContents
Next i
'no more openings
If collLimit(sActivity) = 0 Then
For i = iName + 1 To .Cells(1, 1).CurrentRegion.Rows.Count
If .Cells(i, 2).Value = sActivity Then .Cells(i, 2).ClearContents
Next i
End If
NextName:
Next iName
End With
'put on sheets
With wsNames
For iName = 2 To .Cells(1, 1).CurrentRegion.Rows.Count
sName = .Cells(iName, 1).Value
sActivity = .Cells(iName, 2).Value
'not assigned
If Len(sActivity) = 0 Then GoTo NextName2
If pvtSites(sActivity) = 1 Then
Worksheets(sActivity).Cells(Worksheets(sActivity).Rows.Count, 1).End(xlUp).Offset(1, 0).Value = sName
Else
For i = 1 To pvtSites(sActivity)
If Worksheets(sActivity & " " & i).Cells(1, 1).CurrentRegion.Count - 1 < pvtCapacity(sActivity) Then
'room on this sheet
Worksheets(sActivity & " " & i).Cells(Worksheets(sActivity & " " & i).Rows.Count, 1).End(xlUp).Offset(1, 0).Value = sName
Exit For
End If
Next i
End If
NextName2:
Next iName
End With
'remove working copy
' Call pvtDeleteSheet(wsNames.Name)
End Sub
Private Sub pvtDeleteSheet(s As String)
'remove working copy
On Error Resume Next
Application.DisplayAlerts = False
Worksheets(s).Delete
Application.DisplayAlerts = True
On Error GoTo 0
End Sub
Private Function pvtCapacity(s As String) As Long
pvtCapacity = 0
On Error Resume Next
pvtCapacity = Application.WorksheetFunction.VLookup(s, rCapacity, 2, False)
On Error GoTo 0
End Function
Private Function pvtSites(s As String) As Long
pvtSites = 0
On Error Resume Next
pvtSites = Application.WorksheetFunction.VLookup(s, rCapacity, 3, False)
On Error GoTo 0
End Function