1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
"""
Movie renege example
Covers:
- Resources: Resource
- Condition events
- Shared events
Scenario:
A movie theatre has one ticket counter selling tickets for three
movies (next show only). When a movie is sold out, all people waiting
to buy tickets for that movie renege (leave queue).
"""
import collections
import random
import simpy
RANDOM_SEED = 42
TICKETS = 50 # Number of tickets per movie
SIM_TIME = 120 # Simulate until
def moviegoer(env, movie, num_tickets, theater):
"""A moviegoer tries to by a number of tickets (*num_tickets*) for
a certain *movie* in a *theater*.
If the movie becomes sold out, she leaves the theater. If she gets
to the counter, she tries to buy a number of tickets. If not enough
tickets are left, she argues with the teller and leaves.
If at most one ticket is left after the moviegoer bought her
tickets, the *sold out* event for this movie is triggered causing
all remaining moviegoers to leave.
"""
with theater.counter.request() as my_turn:
# Wait until its our turn or until the movie is sold out
result = yield my_turn | theater.sold_out[movie]
# Check if it's our turn of if movie is sold out
if my_turn not in result:
theater.num_renegers[movie] += 1
env.exit()
# Check if enough tickets left.
if theater.available[movie] < num_tickets:
# Moviegoer leaves after some discussion
yield env.timeout(0.5)
env.exit()
# Buy tickets
theater.available[movie] -= num_tickets
if theater.available[movie] < 2:
# Trigger the "sold out" event for the movie
theater.sold_out[movie].succeed()
theater.when_sold_out[movie] = env.now
theater.available[movie] = 0
yield env.timeout(1)
def customer_arrivals(env, theater):
"""Create new *moviegoers* until the sim time reaches 120."""
while True:
yield env.timeout(random.expovariate(1 / 0.5))
movie = random.choice(theater.movies)
num_tickets = random.randint(1, 6)
if theater.available[movie]:
env.process(moviegoer(env, movie, num_tickets, theater))
Theater = collections.namedtuple('Theater', 'counter, movies, available, '
'sold_out, when_sold_out, '
'num_renegers')
# Setup and start the simulation
print('Movie renege')
random.seed(RANDOM_SEED)
env = simpy.Environment()
# Create movie theater
counter = simpy.Resource(env, capacity=1)
movies = ['Python Unchained', 'Kill Process', 'Pulp Implementation']
available = {movie: TICKETS for movie in movies}
sold_out = {movie: env.event() for movie in movies}
when_sold_out = {movie: None for movie in movies}
num_renegers = {movie: 0 for movie in movies}
theater = Theater(counter, movies, available, sold_out, when_sold_out,
num_renegers)
# Start process and run
env.process(customer_arrivals(env, theater))
env.run(until=SIM_TIME)
# Analysis/results
for movie in movies:
if theater.sold_out[movie]:
print('Movie "%s" sold out %.1f minutes after ticket counter '
'opening.' % (movie, theater.when_sold_out[movie]))
print(' Number of people leaving queue when film sold out: %s' %
theater.num_renegers[movie])
|