For context: Vistaprint produces monitors and printers for computers. In the past, only some of them were inspected on a sampling basis. However, the new plan is that they all will be inspected before they are released. Under this plan, the monitors and printers will be brought to the inspection station one at a time as they are completed. For monitors, the interarrival time (the time between consecutive arrivals) will have a uniform distribution between 5 and 10 minutes. For printers, the interarrival time will be a constant 7.5 minutes. The inspection station has two inspectors. One inspector works on only monitors and the other one inspects only computers. In either case, the inspection time has an exponential distribution with a mean of 5 minutes. Before beginning the new plan, management wants an evaluation made of how long the monitors and printers will be held up waiting at the inspection station. This is what we gotta solve.

#Let's make a function of n (the number of printers or monitors we want to simulate),
#interarrival_fn (the time inbetween each item arrival), and inspection_fn(the inspection time)
#The latter two will be random number-generating functions themselves which we will define later. 
simulate_queue <- function(n, interarrival_fn, inspection_fn) {
  arrival_times <- cumsum(sapply(1:n, function(i) interarrival_fn()))
  start_times <- numeric(n)
  end_times <- numeric(n)

#Now we design a loop to give the start and end times for n arrivals
#note* there is no wait time for the first item. Inspection begins right as it arrives
  for (i in 1:n) {
    if (i == 1) {
      start_times[i] <- arrival_times[i]
    } else {
      start_times[i] <- max(arrival_times[i], end_times[i-1])
    }
    end_times[i] <- start_times[i] + inspection_fn()}
  
  #Calculate wait times based on end and arrival times
  wait_times <- end_times - arrival_times
  
  #Create a data frame with all of this new timing information
  return(data.frame(arrival = arrival_times, start = start_times, end = end_times, wait = wait_times))
}

#Now we can run the simulations, in which we'll generate random numbers 
#So we have to set a seed to make sure we all generate the same numbers
set.seed(1)

# Simulate 100 monitor arrivals. Picks a random number between 5 and 10 for 
#inter-arrival times and a random number from an exponential distrubution with a mean of 5
#as our inspection time
monitor_100 <- simulate_queue(
  n = 100,
  interarrival_fn = function() runif(1, 5, 10),
  inspection_fn = function() rexp(1, rate = 1/5)
)

#Simulate 100 printer arrivals
printer_100 <- simulate_queue(
  n = 100,
  interarrival_fn = function() 7.5,
  inspection_fn = function() rexp(1, rate = 1/5)
)

#Get results from simulations
cat("Monitor 100 arrivals:\n")
## Monitor 100 arrivals:
cat("Avg Wait:", mean(monitor_100$wait), "\nSD:", sd(monitor_100$wait), "\n\n")
## Avg Wait: 7.76478 
## SD: 7.096214
cat("Printer 100 arrivals:\n")
## Printer 100 arrivals:
cat("Avg Wait:", mean(printer_100$wait), "\nSD:", sd(printer_100$wait), "\n\n")
## Avg Wait: 6.307304 
## SD: 4.822603
#Repeat for n=1,000
monitor_1000 <- simulate_queue(1000, function() runif(1, 5, 10), function() rexp(1, rate = 1/5))
printer_1000 <- simulate_queue(1000, function() 7.5, function() rexp(1, rate = 1/5))

cat("Monitor 1000 arrivals:\n")
## Monitor 1000 arrivals:
cat("Avg Wait:", mean(monitor_1000$wait), "\nSD:", sd(monitor_1000$wait), "\n\n")
## Avg Wait: 9.884918 
## SD: 10.39886
cat("Printer 1000 arrivals:\n")
## Printer 1000 arrivals:
cat("Avg Wait:", mean(printer_1000$wait), "\nSD:", sd(printer_1000$wait), "\n\n")
## Avg Wait: 10.47915 
## SD: 9.665579