Movie Renege

Covers:

  • Resources
  • Event operators
  • Shared events

This examples models a movie theater with one ticket counter selling tickets for three movies (next show only). People arrive at random times and try to buy a random number (1–6) tickets for a random movie. When a movie is sold out, all people waiting to buy a ticket for that movie renege (leave the queue).

The movie theater is just a type to assemble all the related data (movies, the counter, tickets left, collected data, ...). The counter is a Resource with a capacity of one.

The moviegoer process function starts waiting until either it’s his turn (it acquires the counter resource) or until the sold out signal is triggered. If the latter is the case it reneges (leaves the queue). If it gets to the counter, it tries to buy some tickets. This might not be successful, e.g. if the process tries to buy 5 tickets but only 3 are left. If less then two tickets are left after the ticket purchase, the sold out signal is triggered.

Moviegoers are generated by the customer arrivals process. It also chooses a movie and the number of tickets for the moviegoer.

using SimJulia
using Distributions
using Compat

const RANDOM_SEED = 158
const TICKETS = 50  # Number of tickets per movie
const SIM_TIME = 120.0  # Simulate until

# Create movie theater
type Theater
  movies :: Vector{ASCIIString}
  counter :: Resource
  available :: Dict{ASCIIString, Int}
  sold_out :: Dict{ASCIIString, Event}
  when_sold_out :: Dict{ASCIIString, Float64}
  num_renegers :: Dict{ASCIIString, Int}
  function Theater(env)
    theater = new()
    theater.movies = ASCIIString["Julia Unchained", "Kill Process", "Pulp Implementation"]
    theater.counter = Resource(env, 1)
    theater.available = @compat Dict("Julia Unchained" => TICKETS, "Kill Process" => TICKETS, "Pulp Implementation" => TICKETS)
    theater.sold_out = @compat Dict("Julia Unchained" => Event(env), "Kill Process" => Event(env), "Pulp Implementation" => Event(env))
    theater.when_sold_out = @compat Dict("Julia Unchained" => typemax(Float64), "Kill Process" => typemax(Float64), "Pulp Implementation" => typemax(Float64))
    theater.num_renegers = @compat Dict("Julia Unchained" => 0, "Kill Process" => 0, "Pulp Implementation" => 0)
    return theater
  end
end

function moviegoer(env::Environment, movie::ASCIIString, num_tickets::Int, theater::Theater)
  req = Request(theater.counter)
  result = yield(req | theater.sold_out[movie])
  if in(theater.sold_out[movie], keys(result))
    theater.num_renegers[movie] += 1
    cancel(theater.counter, req)
  elseif theater.available[movie] < num_tickets
    yield(Timeout(env, 0.5))
    yield(Release(theater.counter))
  else
    theater.available[movie] -= num_tickets
    if theater.available[movie] < 2
      succeed(theater.sold_out[movie])
      theater.when_sold_out[movie] = now(env)
      theater.available[movie] = 0
    end
    yield(Timeout(env, 1.0))
    yield(Release(theater.counter))
  end
end

function customer_arrivals(env::Environment, theater::Theater)
  t = Exponential(0.5)
  d = DiscreteUniform(1, 3)
  n = DiscreteUniform(1, 6)
  while true
    yield(Timeout(env, rand(t)))
    movie = theater.movies[rand(d)]
    num_tickets = rand(n)
    if theater.available[movie] > 0
      Process(env, moviegoer, movie, num_tickets, theater)
    end
  end
end

# Setup and start the simulation
println("Movie renege")
srand(RANDOM_SEED)
env = Environment()
theater = Theater(env)

# Start process and run
Process(env, customer_arrivals, theater)
run(env, SIM_TIME)

# Analysis/results
for movie in theater.movies
  if processed(theater.sold_out[movie])
    println("Movie $movie sold out $(theater.when_sold_out[movie]) minutes after ticket counter opening.")
    println("  Number of people leaving queue when film sold out: $(theater.num_renegers[movie])")
  end
end

The simulation’s output:

Movie renege
Movie Julia Unchained sold out 47.08786185479453 minutes after ticket counter opening.
  Number of people leaving queue when film sold out: 17
Movie Kill Process sold out 38.08786185479453 minutes after ticket counter opening.
  Number of people leaving queue when film sold out: 17
Movie Pulp Implementation sold out 48.08786185479453 minutes after ticket counter opening.
  Number of people leaving queue when film sold out: 10