Bank queue
A simulated day at a bank, minute by minute: random customers from an EML generator, one first-come-first-served line with a limit, a few tellers; waits, people turned away, how busy the tellers were, Little's law exactly, and the same customers with 1 to 5 tellers.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
A simulated day at a bank, minute by minute. Random customers come, wait in one line in the order they came, and go to the first free teller. The line has a limit, and someone who finds it full leaves. It reports the waits, the people turned away, how busy the tellers were, and the same customers with 1 to 5 tellers side by side. It starts with 2 tellers, 8 hours, a customer in 40% of minutes needing 2 to 7 minutes each, and room for 10 in line.
main.eml- the menu, settings, and the reportsbank.eml- the random customers and the minute-by-minute simulation
How each part works:
- Customers: each minute a linear congruential generator (the constants of Numerical Recipes, mod 2^32) decides whether someone comes, and if so how long they need. Only its top 16 bits are used, since the low bits of such a generator repeat quickly. The customers are drawn before anything else, so every number of tellers and every line limit sees exactly the same people.
- Each minute: first every free teller calls the front of the line - a first-come-first-served queue, as in the corpus case
simple-queue. Then the minute's customer, if any, goes straight to a teller who is still free, or joins the line, or leaves when the line already holds its limit. As the corpus casebounded-queue-backpressuresays, a full queue has to drop something; here it is the newcomer. The day runs on past closing until the line is empty. - Little's law in its exact form: the line's length added up over every minute equals all the customers' waits added up. The program counts both separately and prints both.
What is checked: menu choices 1 to 5; 1 to 5 tellers; 30 to 600 minutes open; a 1 to 100% chance of a customer each minute; a service time from 1 to 30 minutes, the longest no shorter than the shortest; room for 0 to 50 in line; a seed from 0 to 999999. An empty answer keeps a setting as it was.
Sessions: sessions/basic.in gives: - the starting day: 189 customers, all served, an average wait of 4.01 minutes; - the same customers with 1 to 5 tellers - one teller turns 80 away; - the first 20 minutes; - 4 hours at 60%, 2 to 10 minutes, room for 3: 55 turned away with 2 tellers, and the day with 1 to 5.
sessions/bad-input.in gives: - menu choices 0 and x; - every setting out of range once (tellers 6, 0 and abc; 29 and 601 minutes; 0% and 101%; a 31-minute service; a longest below the shortest; room for 51; seed 1000000); - then 1 teller, a customer every minute needing 5 minutes, and nobody able to wait: exactly one in five served.
Built on the verified corpus cases simple-queue (a queue served in the order people came) and bounded-queue-backpressure (what a full queue has to drop).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal== Bank queue ==
A day at a bank, minute by minute: random customers, one line, a few tellers.
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 0
Pick a number from 1 to 5.
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> x
Pick a number from 1 to 5.
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 4
Settings, one at a time; an empty answer keeps the old value.
tellers, now 2 (1 to 5)> 6
Type a whole number from 1 to 5.
tellers, now 2 (1 to 5)> 0
Type a whole number from 1 to 5.
tellers, now 2 (1 to 5)> abc
Type a whole number from 1 to 5.
tellers, now 2 (1 to 5)> 1
minutes open, now 480 (30 to 600)> 29
Type a whole number from 30 to 600.
minutes open, now 480 (30 to 600)> 601
Type a whole number from 30 to 600.
minutes open, now 480 (30 to 600)> 60
chance of a customer each minute, %, now 40 (1 to 100)> 0
Type a whole number from 1 to 100.
chance of a customer each minute, %, now 40 (1 to 100)> 101
Type a whole number from 1 to 100.
chance of a customer each minute, %, now 40 (1 to 100)> 100
shortest service, minutes, now 2 (1 to 30)> 31
Type a whole number from 1 to 30.
shortest service, minutes, now 2 (1 to 30)> 5
longest service, minutes, now 7 (5 to 30)> 4
Type a whole number from 5 to 30.
longest service, minutes, now 7 (5 to 30)> 5
room in the line, now 10 (0 to 50)> 51
Type a whole number from 0 to 50.
room in the line, now 10 (0 to 50)> 0
seed, now 2026 (0 to 999999)> 1000000
Type a whole number from 0 to 999999.
seed, now 2026 (0 to 999999)> 7
Now: 1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.
1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 1
60 customers came; 12 were served and 48 turned away, finding no room in the line.
Average wait 0.00 minutes; the longest 0. The line was at most 0 long.
The last customer left at 10:00; the tellers were busy 100.00% of that time.
Little's law: the line held 0 customer-minutes in all, and the customers waited 0 minutes in all - the same thing counted two ways.
1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 3
The first 20 minutes:
9:00 one arrives and goes to teller 1 - 0 in line
9:01 one arrives, finds no room in the line and leaves - 0 in line
9:02 one arrives, finds no room in the line and leaves - 0 in line
9:03 one arrives, finds no room in the line and leaves - 0 in line
9:04 one arrives, finds no room in the line and leaves - 0 in line
9:05 one arrives and goes to teller 1 - 0 in line
9:06 one arrives, finds no room in the line and leaves - 0 in line
9:07 one arrives, finds no room in the line and leaves - 0 in line
9:08 one arrives, finds no room in the line and leaves - 0 in line
9:09 one arrives, finds no room in the line and leaves - 0 in line
9:10 one arrives and goes to teller 1 - 0 in line
9:11 one arrives, finds no room in the line and leaves - 0 in line
9:12 one arrives, finds no room in the line and leaves - 0 in line
9:13 one arrives, finds no room in the line and leaves - 0 in line
9:14 one arrives, finds no room in the line and leaves - 0 in line
9:15 one arrives and goes to teller 1 - 0 in line
9:16 one arrives, finds no room in the line and leaves - 0 in line
9:17 one arrives, finds no room in the line and leaves - 0 in line
9:18 one arrives, finds no room in the line and leaves - 0 in line
9:19 one arrives, finds no room in the line and leaves - 0 in line
1 teller, open 60 minutes, a customer in 100% of minutes, 5 minutes each, nobody can wait in line, seed 7.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 5
Bye.
What was typed (24 lines)
0
x
4
6
0
abc
1
29
601
60
0
101
100
31
5
4
5
51
0
1000000
7
1
3
5
basic
interpreter: byte-equal== Bank queue ==
A day at a bank, minute by minute: random customers, one line, a few tellers.
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 1
189 customers came; 189 were served and 0 turned away, finding no room in the line.
Average wait 4.01 minutes; the longest 14. The line was at most 7 long.
The last customer left at 17:16; the tellers were busy 88.61% of that time.
Little's law: the line held 757 customer-minutes in all, and the customers waited 757 minutes in all - the same thing counted two ways.
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 2
189 customers, the same ones each time:
tellers served away average wait longest busy
1 109 80 41.51 58 99.81%
2 189 0 4.01 14 88.61%
3 189 0 0.32 4 60.54%
4 189 0 0.06 3 45.50%
5 189 0 0.01 2 36.40%
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 3
The first 20 minutes:
9:00 quiet - 0 in line
9:01 one arrives and goes to teller 1 - 0 in line
9:02 quiet - 0 in line
9:03 quiet - 0 in line
9:04 one arrives and goes to teller 2 - 0 in line
9:05 quiet - 0 in line
9:06 quiet - 0 in line
9:07 one arrives and goes to teller 1 - 0 in line
9:08 quiet - 0 in line
9:09 quiet - 0 in line
9:10 one arrives and goes to teller 1 - 0 in line
9:11 quiet - 0 in line
9:12 one arrives and goes to teller 2 - 0 in line
9:13 quiet - 0 in line
9:14 quiet - 0 in line
9:15 one arrives and goes to teller 1 - 0 in line
9:16 one arrives and goes to teller 2 - 0 in line
9:17 quiet - 0 in line
9:18 quiet - 0 in line
9:19 one arrives and waits - 1 in line
2 tellers, open 480 minutes, a customer in 40% of minutes, 2 to 7 minutes each, room for 10 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 4
Settings, one at a time; an empty answer keeps the old value.
tellers, now 2 (1 to 5)>
minutes open, now 480 (30 to 600)> 240
chance of a customer each minute, %, now 40 (1 to 100)> 60
shortest service, minutes, now 2 (1 to 30)>
longest service, minutes, now 7 (2 to 30)> 10
room in the line, now 10 (0 to 50)> 3
seed, now 2026 (0 to 999999)>
Now: 2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.
2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 1
139 customers came; 84 were served and 55 turned away, finding no room in the line.
Average wait 7.20 minutes; the longest 14. The line was at most 3 long.
The last customer left at 13:14; the tellers were busy 99.21% of that time.
Little's law: the line held 605 customer-minutes in all, and the customers waited 605 minutes in all - the same thing counted two ways.
2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 2
139 customers, the same ones each time:
tellers served away average wait longest busy
1 41 98 17.24 29 99.63%
2 84 55 7.20 14 99.21%
3 122 17 3.11 10 96.18%
4 136 3 1.07 7 83.20%
5 139 0 0.17 3 68.26%
2 tellers, open 240 minutes, a customer in 60% of minutes, 2 to 10 minutes each, room for 3 in line, seed 2026.
1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit
choice> 5
Bye.
What was typed (14 lines)
1
2
3
4
240
60
10
3
1
2
5
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P075 bank queue: a simulated day at a bank with random customers, one
# line and a few tellers - the waits, the people turned away when the line
# is full, how busy the tellers were, and the same customers with 1 to 5
# tellers side by side.
import bank
def trim(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def number(s):
if len(s) == 0 or len(s) > 6:
return -1
0 => n
for c in s:
if not (c >= "0" and c <= "9"):
return -1
n * 10 + int(c) => n
return n
def lpad(s, n):
while len(s) < n:
" " + s => s
return s
def decimal(a, b):
# a / b to two places, rounded half up, for whole a >= 0 and b > 0.
200 * a + b => n
2 * b => d
0 => q
while n >= d:
d => m
1 => k
while m + m <= n:
m + m => m
k + k => k
n - m => n
q + k => q
0 => whole
q => r
while r >= 100:
r - 100 => r
whole + 1 => whole
if r < 10:
return str(whole) + ".0" + str(r)
return str(whole) + "." + str(r)
def clock(m):
# Minutes after opening at 9:00 as a time of day.
9 => h
m => r
while r >= 60:
r - 60 => r
h + 1 => h
"" => z
if r < 10:
"0" => z
return str(h) + ":" + z + str(r)
def ask(prompt, low, high):
while True:
trim(input(prompt + " (" + str(low) + " to " + str(high) + ")> ")) => a
if a == "":
return -1
number(a) => n
if n >= low and n <= high:
return n
("Type a whole number from " + str(low) + " to " + str(high) + ".") ^0
def settings_text(s):
"1 teller" => who
if s[0] > 1:
str(s[0]) + " tellers" => who
"nobody can wait in line" => room
if s[5] > 0:
"room for " + str(s[5]) + " in line" => room
str(s[3]) + " to " + str(s[4]) => service
if s[3] == s[4]:
str(s[3]) => service
return who + ", open " + str(s[1]) + " minutes, a customer in " + str(s[2]) + "% of minutes, " + service + " minutes each, " + room + ", seed " + str(s[6])
def people_of(s):
return bank.customers(s[1], s[2], s[3], s[4], s[6])
def day(s):
people_of(s) => people
if len(people) == 0:
"Nobody came all day." ^0
return
bank.simulate(people, s[0], s[5], 0) => r
(str(len(people)) + " customers came; " + str(r[0]) + " were served and " + str(r[1]) + " turned away, finding no room in the line.") ^0
if r[0] > 0:
("Average wait " + decimal(r[2], r[0]) + " minutes; the longest " + str(r[3]) + ". The line was at most " + str(r[4]) + " long.") ^0
("The last customer left at " + clock(r[6]) + "; the tellers were busy " + decimal(100 * r[5], s[0] * r[6]) + "% of that time.") ^0
("Little's law: the line held " + str(r[7]) + " customer-minutes in all, and the customers waited " + str(r[2]) + " minutes in all - the same thing counted two ways.") ^0
def compare(s):
people_of(s) => people
if len(people) == 0:
"Nobody came all day." ^0
return
(str(len(people)) + " customers, the same ones each time:") ^0
" tellers served away average wait longest busy" ^0
for k in [1:5]:
bank.simulate(people, k, s[5], 0) => r
"-" => avg
if r[0] > 0:
decimal(r[2], r[0]) => avg
(" " + lpad(str(k), 7) + lpad(str(r[0]), 8) + lpad(str(r[1]), 6) + lpad(avg, 14) + lpad(str(r[3]), 9) + lpad(decimal(100 * r[5], k * r[6]) + "%", 8)) ^0
def opening(s):
people_of(s) => people
bank.simulate(people, s[0], s[5], 20) => r
"The first 20 minutes:" ^0
for e in r[8]:
"quiet" => what
if e[1] != "":
e[1][0:len(e[1]) - 2] => what
(" " + clock(e[0]) + " " + what + " - " + str(e[2]) + " in line") ^0
def change(s):
"Settings, one at a time; an empty answer keeps the old value." ^0
[["tellers", 1, 5], ["minutes open", 30, 600], ["chance of a customer each minute, %", 1, 100], ["shortest service, minutes", 1, 30], ["longest service, minutes", 1, 30], ["room in the line", 0, 50], ["seed", 0, 999999]] => qs
[0] * 7 => out
for k in [0:6]:
qs[k] => q
q[1] => low
if k == 4:
out[3] => low
ask(q[0] + ", now " + str(s[k]), low, q[2]) => v
if v == -1:
s[k] => v
if k == 4 and v < low:
low => v
v => out[k]
("Now: " + settings_text(out) + ".") ^0
return out
[2, 480, 40, 2, 7, 10, 2026] => settings
"== Bank queue ==" ^0
"A day at a bank, minute by minute: random customers, one line, a few tellers." ^0
True => running
while running:
"" ^0
(settings_text(settings) + ".") ^0
"1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit" ^0
trim(input("choice> ")) => choice
if choice == "1":
day(settings)
elif choice == "2":
compare(settings)
elif choice == "3":
opening(settings)
elif choice == "4":
change(settings) => settings
elif choice == "5":
False => running
else:
"Pick a number from 1 to 5." ^0
"Bye." ^0
Python projection (main.py)
import bank
def trim(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def number(s):
if len(s) == 0 or len(s) > 6:
return -1
n = 0
for c in s:
if not (c >= "0" and c <= "9"):
return -1
n = n * 10 + int(c)
return n
def lpad(s, n):
while len(s) < n:
s = " " + s
return s
def decimal(a, b):
n = 200 * a + b
d = 2 * b
q = 0
while n >= d:
m = d
k = 1
while m + m <= n:
m = m + m
k = k + k
n = n - m
q = q + k
whole = 0
r = q
while r >= 100:
r = r - 100
whole = whole + 1
if r < 10:
return str(whole) + ".0" + str(r)
return str(whole) + "." + str(r)
def clock(m):
h = 9
r = m
while r >= 60:
r = r - 60
h = h + 1
z = ""
if r < 10:
z = "0"
return str(h) + ":" + z + str(r)
def ask(prompt, low, high):
while True:
a = trim(input(prompt + " (" + str(low) + " to " + str(high) + ")> "))
if a == "":
return -1
n = number(a)
if n >= low and n <= high:
return n
print("Type a whole number from " + str(low) + " to " + str(high) + ".")
def settings_text(s):
who = "1 teller"
if s[0] > 1:
who = str(s[0]) + " tellers"
room = "nobody can wait in line"
if s[5] > 0:
room = "room for " + str(s[5]) + " in line"
service = str(s[3]) + " to " + str(s[4])
if s[3] == s[4]:
service = str(s[3])
return who + ", open " + str(s[1]) + " minutes, a customer in " + str(s[2]) + "% of minutes, " + service + " minutes each, " + room + ", seed " + str(s[6])
def people_of(s):
return bank.customers(s[1], s[2], s[3], s[4], s[6])
def day(s):
people = people_of(s)
if len(people) == 0:
print("Nobody came all day.")
return
r = bank.simulate(people, s[0], s[5], 0)
print(str(len(people)) + " customers came; " + str(r[0]) + " were served and " + str(r[1]) + " turned away, finding no room in the line.")
if r[0] > 0:
print("Average wait " + decimal(r[2], r[0]) + " minutes; the longest " + str(r[3]) + ". The line was at most " + str(r[4]) + " long.")
print("The last customer left at " + clock(r[6]) + "; the tellers were busy " + decimal(100 * r[5], s[0] * r[6]) + "% of that time.")
print("Little's law: the line held " + str(r[7]) + " customer-minutes in all, and the customers waited " + str(r[2]) + " minutes in all - the same thing counted two ways.")
def compare(s):
people = people_of(s)
if len(people) == 0:
print("Nobody came all day.")
return
print(str(len(people)) + " customers, the same ones each time:")
print(" tellers served away average wait longest busy")
for k in range(1, 6):
r = bank.simulate(people, k, s[5], 0)
avg = "-"
if r[0] > 0:
avg = decimal(r[2], r[0])
print(" " + lpad(str(k), 7) + lpad(str(r[0]), 8) + lpad(str(r[1]), 6) + lpad(avg, 14) + lpad(str(r[3]), 9) + lpad(decimal(100 * r[5], k * r[6]) + "%", 8))
def opening(s):
people = people_of(s)
r = bank.simulate(people, s[0], s[5], 20)
print("The first 20 minutes:")
for e in r[8]:
what = "quiet"
if e[1] != "":
what = e[1][0:len(e[1]) - 2]
print(" " + clock(e[0]) + " " + what + " - " + str(e[2]) + " in line")
def change(s):
print("Settings, one at a time; an empty answer keeps the old value.")
qs = [["tellers", 1, 5], ["minutes open", 30, 600], ["chance of a customer each minute, %", 1, 100], ["shortest service, minutes", 1, 30], ["longest service, minutes", 1, 30], ["room in the line", 0, 50], ["seed", 0, 999999]]
out = [0] * 7
for k in range(0, 7):
q = qs[k]
low = q[1]
if k == 4:
low = out[3]
v = ask(q[0] + ", now " + str(s[k]), low, q[2])
if v == -1:
v = s[k]
if k == 4 and v < low:
v = low
out[k] = v
print("Now: " + settings_text(out) + ".")
return out
settings = [2, 480, 40, 2, 7, 10, 2026]
print("== Bank queue ==")
print("A day at a bank, minute by minute: random customers, one line, a few tellers.")
running = True
while running:
print("")
print(settings_text(settings) + ".")
print("1) the day 2) 1 to 5 tellers 3) the first 20 minutes 4) change settings 5) quit")
choice = trim(input("choice> "))
if choice == "1":
day(settings)
elif choice == "2":
compare(settings)
elif choice == "3":
opening(settings)
elif choice == "4":
settings = change(settings)
elif choice == "5":
running = False
else:
print("Pick a number from 1 to 5.")
print("Bye.")
bank.eml
eml# P075 bank queue - a day at a bank, minute by minute. Customers arrive at
# random, wait in one line in the order they came (the corpus case
# simple-queue), and go to the first free teller. The line has a limit;
# a customer who finds it full is turned away (the corpus case
# bounded-queue-backpressure: a full queue has to drop something, and here
# it is the newcomer).
def draw(x):
# One step of a linear congruential generator (the constants of
# Numerical Recipes, mod 2^32): [next state, its top 16 bits]. The low
# bits of such a generator repeat quickly, so only the top ones are
# used; x / 65536 divides by a power of two below 2^53, which is exact.
(1664525 * x + 1013904223) % 4294967296 => x
return [x, int(x / 65536)]
def customers(open_for, chance, low, high, seed):
# Who comes, decided before anything else so that every number of
# tellers and every line limit sees the same customers: each minute
# someone arrives with `chance` percent probability, and needs a
# service time from low to high minutes. Returns [[arrival, service]].
[] => out
seed => x
for t in [0:open_for - 1]:
draw(x) => d
d[0] => x
if d[1] % 100 < chance:
draw(x) => e
e[0] => x
out + [[t, low + e[1] % (high - low + 1)]] => out
return out
def simulate(people, tellers, limit, show):
# Minute by minute until everyone is served. First each teller who is
# free calls the front of the line. Then the minute's customer, if any,
# goes straight to a teller who is still free, or joins the line, or -
# when the line already holds `limit` - is turned away. Returns
# [served, turned away, total wait, longest wait, longest line, busy
# teller-minutes, minutes until the last leaves, line-minutes (the
# line's length summed over the minutes), log of the first `show`
# minutes as [minute, what happened, line length]].
[0] * tellers => free_at
[] => line
0 => i
0 => served
0 => away
0 => total
0 => longest
0 => most
0 => busy
0 => line_minutes
[] => log
0 => t
while i < len(people) or len(line) > 0:
"" => note
for k in [0:tellers - 1]:
if free_at[k] <= t and len(line) > 0:
line[0] => c
line[1:len(line)] => line
t + c[1] => free_at[k]
busy + c[1] => busy
served + 1 => served
total + t - c[0] => total
if t - c[0] > longest:
t - c[0] => longest
note + "teller " + str(k + 1) + " calls the one from minute " + str(c[0]) + "; " => note
if i < len(people) and people[i][0] == t:
people[i] => c
i + 1 => i
-1 => k
for j in [0:tellers - 1]:
if k == -1 and free_at[j] <= t:
j => k
if k >= 0:
t + c[1] => free_at[k]
busy + c[1] => busy
served + 1 => served
note + "one arrives and goes to teller " + str(k + 1) + "; " => note
elif len(line) < limit:
line + [c] => line
note + "one arrives and waits; " => note
else:
away + 1 => away
note + "one arrives, finds no room in the line and leaves; " => note
if len(line) > most:
len(line) => most
line_minutes + len(line) => line_minutes
if t < show:
log + [[t, note, len(line)]] => log
t + 1 => t
t => last
for k in [0:tellers - 1]:
if free_at[k] > last:
free_at[k] => last
return [served, away, total, longest, most, busy, last, line_minutes, log]
Python projection (bank.py)
def draw(x):
x = (1664525 * x + 1013904223) % 4294967296
return [x, int(x / 65536)]
def customers(open_for, chance, low, high, seed):
out = []
x = seed
for t in range(0, open_for):
d = draw(x)
x = d[0]
if d[1] % 100 < chance:
e = draw(x)
x = e[0]
out = out + [[t, low + e[1] % (high - low + 1)]]
return out
def simulate(people, tellers, limit, show):
free_at = [0] * tellers
line = []
i = 0
served = 0
away = 0
total = 0
longest = 0
most = 0
busy = 0
line_minutes = 0
log = []
t = 0
while i < len(people) or len(line) > 0:
note = ""
for k in range(0, tellers):
if free_at[k] <= t and len(line) > 0:
c = line[0]
line = line[1:len(line)]
free_at[k] = t + c[1]
busy = busy + c[1]
served = served + 1
total = total + t - c[0]
if t - c[0] > longest:
longest = t - c[0]
note = note + "teller " + str(k + 1) + " calls the one from minute " + str(c[0]) + "; "
if i < len(people) and people[i][0] == t:
c = people[i]
i = i + 1
k = -1
for j in range(0, tellers):
if k == -1 and free_at[j] <= t:
k = j
if k >= 0:
free_at[k] = t + c[1]
busy = busy + c[1]
served = served + 1
note = note + "one arrives and goes to teller " + str(k + 1) + "; "
elif len(line) < limit:
line = line + [c]
note = note + "one arrives and waits; "
else:
away = away + 1
note = note + "one arrives, finds no room in the line and leaves; "
if len(line) > most:
most = len(line)
line_minutes = line_minutes + len(line)
if t < show:
log = log + [[t, note, len(line)]]
t = t + 1
last = t
for k in range(0, tellers):
if free_at[k] > last:
last = free_at[k]
return [served, away, total, longest, most, busy, last, line_minutes, log]