This will do it - It's flexible on the number of employees available (can be 10, can be 50!) but it does assume 3 things:
- The list of employees starts on row 3 with no blanks in this list
- The Monday - Friday column C to column L
- The 1st row will indicate whether it's an AM or PM shift
Option Explicit
Sub Work_timetables()
Dim c As Integer, R As Long, iEmployees As Long, ID As String, iField As Integer, bAM As Boolean, lRandomNumber As Long, iNumbersNeeded As Integer, iPicked As Integer
Application.ScreenUpdating = False
c = 3
R = 2
iField = 1
iEmployees = Range("B3:B" & Range("B3").End(xlDown).Row).Rows.Count
Do Until c > 12
Range("C2:L" & iEmployees + 2).AutoFilter Field:=iField, Criteria1:="Yes"
Range("B3:B" & Range("B3").End(xlDown).Row).Copy
Cells(iEmployees + 4, c).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
Range("C2:L" & iEmployees).AutoFilter
c = c + 1
iField = iField + 1
Loop
c = 3
Start:
Do Until c > 12
If c Mod 2 = 0 Then
bAM = False
iNumbersNeeded = 3
End If
If Not c Mod 2 = 0 Then
bAM = True
iNumbersNeeded = 4
End If
If (Cells(1048563, c).End(xlUp).Row - (iEmployees + 3)) < iNumbersNeeded Then
MsgBox "There isn't enough emplooyees available for the " & Cells(2, c).Value & " (" & Cells(1, c).Value & ") shift" & vbNewLine & vbNewLine & "Moving to next shift", vbOKOnly, "Short staffed!"
c = c + 1
GoTo Start
End If
Do Until iPicked = iNumbersNeeded
goLoop:
lRandomNumber = WorksheetFunction.RandBetween(iEmployees + 4, Cells(iEmployees + 4, c).End(xlDown).Row)
If Trim(Range("B" & lRandomNumber).Value) = "" Then
Range("B" & lRandomNumber).Value = "Picked"
Cells(Range("C" & iEmployees + 4).CurrentRegion.Rows.Count + iEmployees + 6 + iPicked, c).Value = Cells(lRandomNumber, c)
iPicked = iPicked + 1
Else
GoTo goLoop
End If
Loop
Range("B" & iEmployees + 4 & ":B" & Range("C" & iEmployees + 4).CurrentRegion.Rows.Count + iEmployees + 4).ClearContents
c = c + 1
iPicked = 0
Loop
Application.ScreenUpdating = True
End Sub