We start by importing the required code pieces:

Turnstile <- R6::R6Class(
  "Turnstile",
  inherit = SimpleQueue
)
SimpleQueue <- R6::R6Class(
  "SimpleQueue",

  public = list(
    initialize = function(id, service_time){

      #initialize with unique turnstile id and zero agents waiting
      private$.id <- id
      private$.service_time <- service_time
      private$.agents_waiting <- 0
    },

    add_agent = function(current_time){
      if(!missing(current_time)){
        private$.agents_waiting <- private$.agents_waiting + 1

        if(is.na(private$.service_complete_at)){
          private$.service_complete_at <- current_time + private$.service_time
        }
      } else {
        stop("Cannot add agent without knowing the current time\n")
      }
      invisible(self)
    },

    remove_agent = function(){

      private$.agents_waiting = private$.agents_waiting - 1
      private$.service_complete_at <- private$.service_complete_at + private$.service_time

      if (private$.agents_waiting <= 0){
        private$.agents_waiting = 0
        private$.service_complete_at <- NA
      }

      invisible(self)
    },

    calculate_wait_time = function(current_time){
      if(missing(current_time)){
        stop("Cannot calculate current wait time without current time\n")
      } else {
        current_wait_time <- (private$.service_time * (private$.agents_waiting - 1)) +
          (private$.service_complete_at - current_time)

        #if we return a negative wait time, that means no one is in line, so
        #replace with zero
        if (is.na(current_wait_time) || current_wait_time < 0){
          current_wait_time <- 0
        }

        return(current_wait_time)
      }
    }
  ),

  active = list(
    id = function(value){
      if(missing(value)){
        private$.id
      } else{
        stop("Cannot set `$turnstile_id` after instantiation\n")
      }
    },

    service_time = function(value){
      if(missing(value)){
        private$.service_time
      } else{
        stop("Cannot change `$service_time` after instantiation\n")
      }
    },

    agents_waiting = function(value){
      if(missing(value)){
        private$.agents_waiting
      } else {
        stop("Cannot set `$agents_waiting`\n")
      }
    },

    service_complete_at = function(value){
      if(missing(value)){
        private$.service_complete_at
      } else{
        stop("cannot set `$service_complete_at`, use `$add_agent\n`")
      }
    }
  ),

  private = list(
    .id = -1,
    .service_time = -1,
    .agents_waiting = -1,
    .service_complete_at = NA
  )
)
choose_turnstile <- function(turnstiles, rule){
  if (rule == "shortest"){
    shortest <- 1 #index into turnstiles, not necessarily turnstile id
    line_length <- turnstiles[[shortest]]$agents_waiting

    #find the first shortest line
    for (i in 1:length(turnstiles)){
      if (turnstiles[[i]]$agents_waiting < line_length){
        shortest <- i
        line_length <- turnstiles[[i]]$agents_waiting
      }
    }

    return(shortest)
  }
}

Testing

We now test the choose_turnstile() function

#define rule (currently it is the only rule defined)
rule = "shortest"

#create three turnstiles
t1 <- Turnstile$new(1, 5)
t2 <- Turnstile$new(2, 5)
t3 <- Turnstile$new(3, 5)

#create a list of turnstiles (necessary to pass into the choose_turnstile function)
turnstiles <- list(t1,t2,t3)

#with no one in line, should pick line 1
stopifnot(choose_turnstile(turnstiles, rule) == 1)

#add two agents to first turnstile at time 0 (with method chaining)
t1$add_agent(0)$add_agent(0)

#now it should pick line 2
stopifnot(choose_turnstile(turnstiles, rule) == 2)

#add a single agent to line 2 at time 0
t2$add_agent(0)

#it should now pick line 3 as the other two lines have agents in them
stopifnot(choose_turnstile(turnstiles, rule) == 3)

#remove an agent from line 2
t2$remove_agent()

#the earliest free line would be line 2
stopifnot(choose_turnstile(turnstiles, rule) == 2)

#if we make it here, the test has passed
print("Pass: Choosing shortest turnstile")
## [1] "Pass: Choosing shortest turnstile"