Elevator
One lift over floors 0 to 9: people call it from a floor to go to another, time moves on in steps, and the lift keeps its direction while there is a reason to go on and turns round when there is none. Statistics show how long people waited, and the same calls can be run again by a lift that takes one passenger at a time, to compare.
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
One lift serves floors 0 to 9. People call it from a floor to go to another; time moves on in steps - one floor of travel, or one stop with the doors open - and the screen shows each move and each stop with who got out and who got in. The lift follows the usual rule for a single car (collective control). The statistics show how long people waited for the lift and how long their whole trip took, and the same calls can be run again from the start by a lift that takes one passenger at a time, in call order, to compare.
main.eml- the menu, the questions and their checks, stepping and running onlift.eml- the rules: one step of time with the direction rule or one passenger at a time, and a whole run of a list of callsreport.eml- the steps as lines, the building, the statistics and the comparison table
How each part works:
- One step with the direction rule: riders whose floor this is get out; the lift keeps its direction while there is a reason to go on - a rider going further that way, a call from a floor further that way, or someone waiting here who wants to go that way. With no reason ahead but one behind, it turns round; with none at all, it goes idle, and an idle lift heads for the earliest call. Whoever waits at the floor and wants to go the lift's way gets in. A stop to let people out or in takes the step.
- So nobody is carried past their floor, and the lift never leaves behind someone who wants to go its way. Someone who wants the other way waits until it comes back: in the basic session P4 waits at floor 7 to go down while the lift goes past on its way up to 8 and 9, and gets in on the way back.
- The corpus case
elevator-simulatormoves one floor per step towards each request of a queue in turn. That is the one-at-a-time lift here, kept for the comparison: the same calls, at the same times, are run from t=0 by both lifts. - Times are whole steps: the wait runs from the call to getting in, the trip from the call to getting out. Averages are worked out in whole numbers and shown to one decimal place, halves rounded up; on a tie for the longest, the lowest passenger number is named.
What is checked: floors from 0 to 9; a destination other than the floor the caller is on; at most 20 calls in a run; 1 to 20 steps at a time. An empty answer cancels.
Sessions: sessions/basic.in has four people call at t=0 - from the ground floor up to 8, from 3 up to 6, from 5 up to 9 and from 7 down to 2; after four steps a fifth calls from floor 1, behind the lift. It shows the building, finishes the run, and shows the statistics and the comparison: an average wait of 9.8 steps with the direction rule, against 19.6 one at a time. sessions/bad-input.in gives menu choices 0 and x; asks for statistics, the comparison and the finish before any call; asks for 0, 21 and abc steps before three idle ones; gives floors 10 and x and the same floor twice; then makes twenty calls at once - two or three on most floors, both ways - and a twenty-first that is refused; shows the building, finishes (an average wait of 14.1 against 88.2 one at a time) and shows the statistics.
Built on the verified corpus case elevator-simulator (a lift that moves one floor per step towards each request of a queue in turn).
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== Elevator ==
One lift, floors 0 to 9. A step of time is one floor of travel or one stop
with the doors open; finish runs on until everyone has arrived.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 0
Pick a number from 1 to 7.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> x
Pick a number from 1 to 7.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 5
Nobody has called the lift yet.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 6
Nobody has called the lift yet.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 3
Nobody is waiting or riding.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 2
how many steps (1 to 20)> 0
Type a number from 1 to 20.
how many steps (1 to 20)> 21
Type a number from 1 to 20.
how many steps (1 to 20)> abc
Type a number from 1 to 20.
how many steps (1 to 20)> 3
t=0-2 idle at floor 0
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 10
Type a floor from 0 to 9.
from floor> x
Type a floor from 0 to 9.
from floor>
Cancelled.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 4
to floor> 4
That is the floor they are on.
to floor>
Cancelled.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 4
to floor> 4
That is the floor they are on.
to floor> 9
P1 waits at floor 4 to go up to 9 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 0
to floor> 9
P2 waits at floor 0 to go up to 9 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 9
to floor> 0
P3 waits at floor 9 to go down to 0 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 2
to floor> 7
P4 waits at floor 2 to go up to 7 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 7
to floor> 2
P5 waits at floor 7 to go down to 2 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 5
to floor> 6
P6 waits at floor 5 to go up to 6 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 6
to floor> 5
P7 waits at floor 6 to go down to 5 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 1
to floor> 8
P8 waits at floor 1 to go up to 8 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 8
to floor> 1
P9 waits at floor 8 to go down to 1 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 3
to floor> 4
P10 waits at floor 3 to go up to 4 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 4
to floor> 3
P11 waits at floor 4 to go down to 3 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 0
to floor> 1
P12 waits at floor 0 to go up to 1 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 9
to floor> 8
P13 waits at floor 9 to go down to 8 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 2
to floor> 3
P14 waits at floor 2 to go up to 3 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 7
to floor> 6
P15 waits at floor 7 to go down to 6 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 5
to floor> 0
P16 waits at floor 5 to go down to 0 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 4
to floor> 9
P17 waits at floor 4 to go up to 9 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 6
to floor> 9
P18 waits at floor 6 to go up to 9 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 3
to floor> 0
P19 waits at floor 3 to go down to 0 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
from floor> 8
to floor> 2
P20 waits at floor 8 to go down to 2 (t=3).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 1
That makes 20 calls, the most for one run.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 4
9 | | P3 -> 0, P13 -> 8
8 | | P9 -> 1, P20 -> 2
7 | | P5 -> 2, P15 -> 6
6 | | P7 -> 5, P18 -> 9
5 | | P6 -> 6, P16 -> 0
4 | | P1 -> 9, P11 -> 3, P17 -> 9
3 | | P10 -> 4, P19 -> 0
2 | | P4 -> 7, P14 -> 3
1 | | P8 -> 8
0 |[ 0]| P2 -> 9, P12 -> 1
t=3: the lift is at floor 0, idle, empty.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 2
how many steps (1 to 20)>
Cancelled.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=3 choice> 3
t=3 floor 0 - in: P2 (to 9), P12 (to 1)
t=4 up to 1
t=5 floor 1 - out: P12 (waited 0, rode 2); in: P8 (to 8)
t=6 up to 2
t=7 floor 2 - in: P4 (to 7), P14 (to 3)
t=8 up to 3
t=9 floor 3 - out: P14 (waited 4, rode 2); in: P10 (to 4)
t=10 up to 4
t=11 floor 4 - out: P10 (waited 6, rode 2); in: P1 (to 9), P17 (to 9)
t=12 up to 5
t=13 floor 5 - in: P6 (to 6)
t=14 up to 6
t=15 floor 6 - out: P6 (waited 10, rode 2); in: P18 (to 9)
t=16 up to 7
t=17 floor 7 - out: P4 (waited 4, rode 10)
t=18 up to 8
t=19 floor 8 - out: P8 (waited 2, rode 14)
t=20 up to 9
t=21 floor 9 - out: P2 (waited 0, rode 18), P1 (waited 8, rode 10), P17 (waited 8, rode 10), P18 (waited 12, rode 6); in: P3 (to 0), P13 (to 8)
t=22 down to 8
t=23 floor 8 - out: P13 (waited 18, rode 2); in: P9 (to 1), P20 (to 2)
t=24 down to 7
t=25 floor 7 - in: P5 (to 2), P15 (to 6)
t=26 down to 6
t=27 floor 6 - out: P15 (waited 22, rode 2); in: P7 (to 5)
t=28 down to 5
t=29 floor 5 - out: P7 (waited 24, rode 2); in: P16 (to 0)
t=30 down to 4
t=31 floor 4 - in: P11 (to 3)
t=32 down to 3
t=33 floor 3 - out: P11 (waited 28, rode 2); in: P19 (to 0)
t=34 down to 2
t=35 floor 2 - out: P20 (waited 20, rode 12), P5 (waited 22, rode 10)
t=36 down to 1
t=37 floor 1 - out: P9 (waited 20, rode 14)
t=38 down to 0
t=39 floor 0 - out: P3 (waited 18, rode 18), P16 (waited 26, rode 10), P19 (waited 30, rode 6)
Everyone has arrived; the lift is free at floor 0.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=40 choice> 5
Calls: 20. Arrived 20, riding 0, waiting 0.
Wait for the lift: average 14.1, longest 30 (P19), over the 20 picked up.
Call to arrival: average 21.8, longest 36 (P3), over the 20 arrived.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=40 choice> 6
The 20 calls again from t=0 (trip = from the call to arrival):
average wait longest wait average trip last arrival
direction rule 14.1 30 21.8 t=39
one at a time 88.2 171 93.0 t=181
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=40 choice> 7
Bye.
What was typed (87 lines)
0
x
5
6
3
2
0
21
abc
3
1
10
x
1
4
4
1
4
4
9
1
0
9
1
9
0
1
2
7
1
7
2
1
5
6
1
6
5
1
1
8
1
8
1
1
3
4
1
4
3
1
0
1
1
9
8
1
2
3
1
7
6
1
5
0
1
4
9
1
6
9
1
3
0
1
8
2
1
4
2
3
5
6
7
basic
interpreter: byte-equal== Elevator ==
One lift, floors 0 to 9. A step of time is one floor of travel or one stop
with the doors open; finish runs on until everyone has arrived.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 1
from floor> 0
to floor> 8
P1 waits at floor 0 to go up to 8 (t=0).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 1
from floor> 3
to floor> 6
P2 waits at floor 3 to go up to 6 (t=0).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 1
from floor> 5
to floor> 9
P3 waits at floor 5 to go up to 9 (t=0).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 1
from floor> 7
to floor> 2
P4 waits at floor 7 to go down to 2 (t=0).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=0 choice> 2
how many steps (1 to 20)> 4
t=0 floor 0 - in: P1 (to 8)
t=1-3 up to 3
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=4 choice> 1
from floor> 1
to floor> 4
P5 waits at floor 1 to go up to 4 (t=4).
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=4 choice> 4
9 | |
8 | |
7 | | P4 -> 2
6 | |
5 | | P3 -> 9
4 | |
3 |[ 1]| P2 -> 6
2 | |
1 | | P5 -> 4
0 | |
t=4: the lift is at floor 3, going up, with P1 -> 8.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=4 choice> 3
t=4 floor 3 - in: P2 (to 6)
t=5-6 up to 5
t=7 floor 5 - in: P3 (to 9)
t=8 up to 6
t=9 floor 6 - out: P2 (waited 4, rode 5)
t=10-11 up to 8
t=12 floor 8 - out: P1 (waited 0, rode 12)
t=13 up to 9
t=14 floor 9 - out: P3 (waited 7, rode 7)
t=15-16 down to 7
t=17 floor 7 - in: P4 (to 2)
t=18-22 down to 2
t=23 floor 2 - out: P4 (waited 17, rode 6)
t=24 down to 1
t=25 floor 1 - in: P5 (to 4)
t=26-28 up to 4
t=29 floor 4 - out: P5 (waited 21, rode 4)
Everyone has arrived; the lift is free at floor 4.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=30 choice> 5
Calls: 5. Arrived 5, riding 0, waiting 0.
Wait for the lift: average 9.8, longest 21 (P5), over the 5 picked up.
Call to arrival: average 16.6, longest 25 (P5), over the 5 arrived.
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=30 choice> 6
The 5 calls again from t=0 (trip = from the call to arrival):
average wait longest wait average trip last arrival
direction rule 9.8 21 16.6 t=29
one at a time 19.6 33 25.2 t=41
1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit
t=30 choice> 7
Bye.
What was typed (22 lines)
1
0
8
1
3
6
1
5
9
1
7
2
2
4
1
1
4
4
3
5
6
7
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# P033 elevator: one lift, floors 0 to 9. People call it from a floor to go
# to another, time moves on in steps, and the lift follows the usual rule for
# a single car (collective control). The statistics show how long people
# waited, and the same calls can be run again by a lift that takes one
# passenger at a time, in call order, to compare.
import lift
import report
20 => most_calls
20 => most_steps
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 whole_number(s):
# The value of s if it is 1 to 3 digits, otherwise -1.
trim(s) => s
if s == "" or len(s) > 3:
return -1
0 => n
for c in s:
if not (c in "0123456789"):
return -1
n * 10 + int(c) => n
return n
def ask_floor(prompt):
# A floor, or -1 when the answer is empty.
while True:
trim(input(prompt)) => answer
if answer == "":
return -1
whole_number(answer) => f
if f >= lift.lowest and f <= lift.highest:
return f
("Type a floor from " + str(lift.lowest) + " to " + str(lift.highest) + ".") ^0
def ask_destination(start):
# A floor other than start, or -1 when the answer is empty.
while True:
ask_floor("to floor> ") => f
if f != start:
return f
"That is the floor they are on." ^0
def call(state, calls):
# Returns [state, calls] with the new caller waiting.
if len(calls) == most_calls:
("That makes " + str(most_calls) + " calls, the most for one run.") ^0
return [state, calls]
ask_floor("from floor> ") => a
if a == -1:
"Cancelled." ^0
return [state, calls]
ask_destination(a) => b
if b == -1:
"Cancelled." ^0
return [state, calls]
len(calls) + 1 => n
calls + [[n, a, b, state[0]]] => calls
state[3] + [[n, a, b, state[0], -1, -1]] => waiting
"up" => way
if b < a:
"down" => way
("P" + str(n) + " waits at floor " + str(a) + " to go " + way + " to " + str(b) + " (t=" + str(state[0]) + ").") ^0
return [[state[0], state[1], state[2], waiting, state[4], state[5]], calls]
def advance(state, n):
[] => events
for k in [1:n]:
lift.step(state, False) => r
r[0] => state
events + [r[1]] => events
for line in report.event_lines(events):
line ^0
return state
def steps(state):
while True:
trim(input("how many steps (1 to " + str(most_steps) + ")> ")) => answer
if answer == "":
"Cancelled." ^0
return state
whole_number(answer) => n
if n >= 1 and n <= most_steps:
return advance(state, n)
("Type a number from 1 to " + str(most_steps) + ".") ^0
def run_to_end(state):
if not lift.busy(state):
"Nobody is waiting or riding." ^0
return state
[] => events
while lift.busy(state):
lift.step(state, False) => r
r[0] => state
events + [r[1]] => events
for line in report.event_lines(events):
line ^0
("Everyone has arrived; the lift is free at floor " + str(state[1]) + ".") ^0
return state
"== Elevator ==" ^0
"One lift, floors 0 to 9. A step of time is one floor of travel or one stop" ^0
"with the doors open; finish runs on until everyone has arrived." ^0
[0, lift.lowest, 0, [], [], []] => state
[] => calls
True => running
while running:
"" ^0
"1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit" ^0
trim(input("t=" + str(state[0]) + " choice> ")) => choice
if choice == "1":
call(state, calls) => r
r[0] => state
r[1] => calls
elif choice == "2":
steps(state) => state
elif choice == "3":
run_to_end(state) => state
elif choice == "4":
report.building(state)
elif choice == "5":
report.statistics(state)
elif choice == "6":
report.compare(calls)
elif choice == "7":
False => running
else:
"Pick a number from 1 to 7." ^0
"Bye." ^0
Python projection (main.py)
import lift
import report
most_calls = 20
most_steps = 20
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 whole_number(s):
s = trim(s)
if s == "" or len(s) > 3:
return -1
n = 0
for c in s:
if not c in "0123456789":
return -1
n = n * 10 + int(c)
return n
def ask_floor(prompt):
while True:
answer = trim(input(prompt))
if answer == "":
return -1
f = whole_number(answer)
if f >= lift.lowest and f <= lift.highest:
return f
print("Type a floor from " + str(lift.lowest) + " to " + str(lift.highest) + ".")
def ask_destination(start):
while True:
f = ask_floor("to floor> ")
if f != start:
return f
print("That is the floor they are on.")
def call(state, calls):
if len(calls) == most_calls:
print("That makes " + str(most_calls) + " calls, the most for one run.")
return [state, calls]
a = ask_floor("from floor> ")
if a == -1:
print("Cancelled.")
return [state, calls]
b = ask_destination(a)
if b == -1:
print("Cancelled.")
return [state, calls]
n = len(calls) + 1
calls = calls + [[n, a, b, state[0]]]
waiting = state[3] + [[n, a, b, state[0], -1, -1]]
way = "up"
if b < a:
way = "down"
print("P" + str(n) + " waits at floor " + str(a) + " to go " + way + " to " + str(b) + " (t=" + str(state[0]) + ").")
return [[state[0], state[1], state[2], waiting, state[4], state[5]], calls]
def advance(state, n):
events = []
for k in range(1, n+1):
r = lift.step(state, False)
state = r[0]
events = events + [r[1]]
for line in report.event_lines(events):
print(line)
return state
def steps(state):
while True:
answer = trim(input("how many steps (1 to " + str(most_steps) + ")> "))
if answer == "":
print("Cancelled.")
return state
n = whole_number(answer)
if n >= 1 and n <= most_steps:
return advance(state, n)
print("Type a number from 1 to " + str(most_steps) + ".")
def run_to_end(state):
if not lift.busy(state):
print("Nobody is waiting or riding.")
return state
events = []
while lift.busy(state):
r = lift.step(state, False)
state = r[0]
events = events + [r[1]]
for line in report.event_lines(events):
print(line)
print("Everyone has arrived; the lift is free at floor " + str(state[1]) + ".")
return state
print("== Elevator ==")
print("One lift, floors 0 to 9. A step of time is one floor of travel or one stop")
print("with the doors open; finish runs on until everyone has arrived.")
state = [0, lift.lowest, 0, [], [], []]
calls = []
running = True
while running:
print("")
print("1) call 2) steps 3) finish 4) building 5) statistics 6) compare 7) quit")
choice = trim(input("t=" + str(state[0]) + " choice> "))
if choice == "1":
r = call(state, calls)
state = r[0]
calls = r[1]
elif choice == "2":
state = steps(state)
elif choice == "3":
state = run_to_end(state)
elif choice == "4":
report.building(state)
elif choice == "5":
report.statistics(state)
elif choice == "6":
report.compare(calls)
elif choice == "7":
running = False
else:
print("Pick a number from 1 to 7.")
print("Bye.")
lift.eml
eml# P033 elevator - the lift and its rules. Floors 0 to 9. One step of time is
# one floor of travel, or one stop with the doors open.
#
# A passenger is [number, from, to, call time, boarding time, arrival time];
# the last two are -1 until they happen. The state of a run is
# [time, floor, direction, waiting, riding, arrived], where the direction is
# 1 going up, -1 going down and 0 idle, and waiting is kept in call order.
0 => lowest
9 => highest
def sign(x):
if x > 0:
return 1
if x < 0:
return -1
return 0
def way(p):
# 1 for a passenger who wants to go up, -1 for one going down.
return sign(p[2] - p[1])
def reason(floor, d, waiting, riding):
# Is there a reason to go on in direction d from this floor: a rider going
# further that way, a call from a floor further that way, or someone
# waiting right here who wants to go that way?
for p in riding:
if sign(p[2] - floor) == d:
return True
for p in waiting:
if sign(p[1] - floor) == d:
return True
if p[1] == floor and way(p) == d:
return True
return False
def step(state, one_at_a_time):
# One step of time. Returns [the new state, what happened], where what
# happened is [kind, time, floor, direction, got out, got in] and kind is
# "doors", "move" or "idle".
state[0] => t
state[1] => floor
state[2] => d
state[3] => waiting
state[4] => riding
[] => out
[] => went_in
if one_at_a_time:
# One passenger at a time, in call order: fetch the first caller,
# take them where they are going, then the next.
if len(riding) > 0 and riding[0][2] == floor:
riding[0] => p
out + [[p[0], p[1], p[2], p[3], p[4], t]] => out
[] => riding
if len(riding) == 0 and len(waiting) > 0 and waiting[0][1] == floor:
waiting[0] => p
[[p[0], p[1], p[2], p[3], t, -1]] => went_in
went_in => riding
waiting[1:len(waiting)] => waiting
0 => d
if len(riding) > 0:
sign(riding[0][2] - floor) => d
elif len(waiting) > 0:
sign(waiting[0][1] - floor) => d
else:
# The direction rule: riders get out at their floor; the lift keeps
# its direction while there is a reason to go on, turns round when
# there is none that way but some the other way, and otherwise goes
# idle. An idle lift heads for the earliest call. Whoever waits here
# and wants to go the lift's way gets in.
[] => kept
for p in riding:
if p[2] == floor:
out + [[p[0], p[1], p[2], p[3], p[4], t]] => out
else:
kept + [p] => kept
kept => riding
if d != 0 and not reason(floor, d, waiting, riding):
if reason(floor, 0 - d, waiting, riding):
0 - d => d
else:
0 => d
if d == 0 and len(waiting) > 0:
waiting[0] => first
if first[1] == floor:
way(first) => d
else:
sign(first[1] - floor) => d
[] => left
for p in waiting:
if p[1] == floor and way(p) == d:
went_in + [[p[0], p[1], p[2], p[3], t, -1]] => went_in
else:
left + [p] => left
left => waiting
riding + went_in => riding
if len(out) > 0 or len(went_in) > 0:
"doors" => kind
elif d != 0:
floor + d => floor
"move" => kind
else:
"idle" => kind
return [[t + 1, floor, d, waiting, riding, state[5] + out], [kind, t, floor, d, out, went_in]]
def busy(state):
return len(state[3]) > 0 or len(state[4]) > 0
def run_all(calls, one_at_a_time):
# Runs the calls [number, from, to, call time] (in call order) from time 0
# with an idle lift at the ground floor, until everyone has arrived.
# Returns the final state.
[0, lowest, 0, [], [], []] => state
0 => k
while k < len(calls) or busy(state):
while k < len(calls) and calls[k][3] == state[0]:
calls[k] => c
[state[0], state[1], state[2], state[3] + [[c[0], c[1], c[2], c[3], -1, -1]], state[4], state[5]] => state
k + 1 => k
step(state, one_at_a_time)[0] => state
return state
Python projection (lift.py)
lowest = 0
highest = 9
def sign(x):
if x > 0:
return 1
if x < 0:
return -1
return 0
def way(p):
return sign(p[2] - p[1])
def reason(floor, d, waiting, riding):
for p in riding:
if sign(p[2] - floor) == d:
return True
for p in waiting:
if sign(p[1] - floor) == d:
return True
if p[1] == floor and way(p) == d:
return True
return False
def step(state, one_at_a_time):
t = state[0]
floor = state[1]
d = state[2]
waiting = state[3]
riding = state[4]
out = []
went_in = []
if one_at_a_time:
if len(riding) > 0 and riding[0][2] == floor:
p = riding[0]
out = out + [[p[0], p[1], p[2], p[3], p[4], t]]
riding = []
if len(riding) == 0 and len(waiting) > 0 and waiting[0][1] == floor:
p = waiting[0]
went_in = [[p[0], p[1], p[2], p[3], t, -1]]
riding = went_in
waiting = waiting[1:len(waiting)]
d = 0
if len(riding) > 0:
d = sign(riding[0][2] - floor)
elif len(waiting) > 0:
d = sign(waiting[0][1] - floor)
else:
kept = []
for p in riding:
if p[2] == floor:
out = out + [[p[0], p[1], p[2], p[3], p[4], t]]
else:
kept = kept + [p]
riding = kept
if d != 0 and not reason(floor, d, waiting, riding):
if reason(floor, 0 - d, waiting, riding):
d = 0 - d
else:
d = 0
if d == 0 and len(waiting) > 0:
first = waiting[0]
if first[1] == floor:
d = way(first)
else:
d = sign(first[1] - floor)
left = []
for p in waiting:
if p[1] == floor and way(p) == d:
went_in = went_in + [[p[0], p[1], p[2], p[3], t, -1]]
else:
left = left + [p]
waiting = left
riding = riding + went_in
if len(out) > 0 or len(went_in) > 0:
kind = "doors"
elif d != 0:
floor = floor + d
kind = "move"
else:
kind = "idle"
return [[t + 1, floor, d, waiting, riding, state[5] + out], [kind, t, floor, d, out, went_in]]
def busy(state):
return len(state[3]) > 0 or len(state[4]) > 0
def run_all(calls, one_at_a_time):
state = [0, lowest, 0, [], [], []]
k = 0
while k < len(calls) or busy(state):
while k < len(calls) and calls[k][3] == state[0]:
c = calls[k]
state = [state[0], state[1], state[2], state[3] + [[c[0], c[1], c[2], c[3], -1, -1]], state[4], state[5]]
k = k + 1
state = step(state, one_at_a_time)[0]
return state
report.eml
eml# P033 elevator - what the screen shows: the steps, the building, the
# statistics and the comparison. Times are whole steps; averages are worked
# out in whole numbers and shown to one decimal place, halves rounded up.
import lift
def quotient(a, b):
return int((a - a % b) / b)
def average(total, n):
# total / n to one decimal place: 11 / 5 is "2.2", 9 / 4 is "2.3".
quotient(total * 20 + n, n * 2) => tenths
return str(quotient(tenths, 10)) + "." + str(tenths % 10)
def going(d):
if d == 1:
return "going up"
if d == -1:
return "going down"
return "idle"
def who(p):
return "P" + str(p[0])
def doors_line(e):
("t=" + str(e[1]) + " floor " + str(e[2]) + " -") => line
if len(e[4]) > 0:
"" => part
for p in e[4]:
if part != "":
part + ", " => part
part + who(p) + " (waited " + str(p[4] - p[3]) + ", rode " + str(p[5] - p[4]) + ")" => part
line + " out: " + part => line
if len(e[5]) > 0:
line + ";" => line
if len(e[5]) > 0:
"" => part
for p in e[5]:
if part != "":
part + ", " => part
part + who(p) + " (to " + str(p[2]) + ")" => part
line + " in: " + part => line
return line
def event_lines(events):
# One line for each stop; a run of moves the same way, or of idle steps,
# becomes one line: "t=3-6 up to 7".
[] => lines
0 => i
while i < len(events):
events[i] => e
if e[0] == "doors":
lines + [doors_line(e)] => lines
i + 1 => i
else:
i => j
while j + 1 < len(events) and events[j + 1][0] == e[0] and events[j + 1][3] == e[3]:
j + 1 => j
"t=" + str(e[1]) => when
if j > i:
when + "-" + str(events[j][1]) => when
if e[0] == "idle":
lines + [when + " idle at floor " + str(e[2])] => lines
elif e[3] == 1:
lines + [when + " up to " + str(events[j][2])] => lines
else:
lines + [when + " down to " + str(events[j][2])] => lines
j + 1 => i
return lines
def trip(p):
return who(p) + " -> " + str(p[2])
def building(state):
lift.highest => f
while f >= lift.lowest:
" " => car
if state[1] == f:
str(len(state[4])) => n
if len(n) < 2:
" " + n => n
"[" + n + "]" => car
"" => calls
for p in state[3]:
if p[1] == f:
if calls != "":
calls + ", " => calls
calls + trip(p) => calls
(" " + str(f) + " |" + car + "|") => line
if calls != "":
line + " " + calls => line
line ^0
f - 1 => f
("t=" + str(state[0]) + ": the lift is at floor " + str(state[1]) + ", " + going(state[2])) => line
if len(state[4]) == 0:
line + ", empty." => line
else:
"" => riders
for p in state[4]:
if riders != "":
riders + ", " => riders
riders + trip(p) => riders
line + ", with " + riders + "." => line
line ^0
def longest(ps, k, j):
# The passenger with the longest time from field k to field j: the
# lowest number on a tie. Returns [time, passenger].
-1 => best
[] => whose
for p in ps:
p[j] - p[k] => v
if v > best or (v == best and p[0] < whose[0]):
v => best
p => whose
return [best, whose]
def total(ps, k, j):
0 => s
for p in ps:
s + p[j] - p[k] => s
return s
def statistics(state):
state[5] => arrived
arrived + state[4] => picked
len(arrived) + len(state[4]) + len(state[3]) => calls
if calls == 0:
"Nobody has called the lift yet." ^0
return 0
("Calls: " + str(calls) + ". Arrived " + str(len(arrived)) + ", riding " + str(len(state[4])) + ", waiting " + str(len(state[3])) + ".") ^0
if len(picked) == 0:
"Nobody has been picked up yet." ^0
else:
longest(picked, 3, 4) => w
("Wait for the lift: average " + average(total(picked, 3, 4), len(picked)) + ", longest " + str(w[0]) + " (" + who(w[1]) + "), over the " + str(len(picked)) + " picked up.") ^0
if len(arrived) > 0:
longest(arrived, 3, 5) => a
("Call to arrival: average " + average(total(arrived, 3, 5), len(arrived)) + ", longest " + str(a[0]) + " (" + who(a[1]) + "), over the " + str(len(arrived)) + " arrived.") ^0
for p in state[3]:
(who(p) + " has waited " + str(state[0] - p[3]) + " so far at floor " + str(p[1]) + ".") ^0
return 0
def right(s, width):
while len(s) < width:
" " + s => s
return s
def row(label, final):
final[5] => ps
0 => last
for p in ps:
if p[5] > last:
p[5] => last
(label + right(average(total(ps, 3, 4), len(ps)), 14) + right(str(longest(ps, 3, 4)[0]), 14) + right(average(total(ps, 3, 5), len(ps)), 14) + right("t=" + str(last), 14)) ^0
def compare(calls):
# The same calls at the same times, run from t=0 by each kind of lift.
if len(calls) == 0:
"Nobody has called the lift yet." ^0
return 0
"call" => what
if len(calls) > 1:
"calls" => what
("The " + str(len(calls)) + " " + what + " again from t=0 (trip = from the call to arrival):") ^0
" average wait longest wait average trip last arrival" ^0
row(" direction rule", lift.run_all(calls, False))
row(" one at a time ", lift.run_all(calls, True))
return 0
Python projection (report.py)
import lift
def quotient(a, b):
return int((a - a % b) / b)
def average(total, n):
tenths = quotient(total * 20 + n, n * 2)
return str(quotient(tenths, 10)) + "." + str(tenths % 10)
def going(d):
if d == 1:
return "going up"
if d == -1:
return "going down"
return "idle"
def who(p):
return "P" + str(p[0])
def doors_line(e):
line = "t=" + str(e[1]) + " floor " + str(e[2]) + " -"
if len(e[4]) > 0:
part = ""
for p in e[4]:
if part != "":
part = part + ", "
part = part + who(p) + " (waited " + str(p[4] - p[3]) + ", rode " + str(p[5] - p[4]) + ")"
line = line + " out: " + part
if len(e[5]) > 0:
line = line + ";"
if len(e[5]) > 0:
part = ""
for p in e[5]:
if part != "":
part = part + ", "
part = part + who(p) + " (to " + str(p[2]) + ")"
line = line + " in: " + part
return line
def event_lines(events):
lines = []
i = 0
while i < len(events):
e = events[i]
if e[0] == "doors":
lines = lines + [doors_line(e)]
i = i + 1
else:
j = i
while j + 1 < len(events) and events[j + 1][0] == e[0] and events[j + 1][3] == e[3]:
j = j + 1
when = "t=" + str(e[1])
if j > i:
when = when + "-" + str(events[j][1])
if e[0] == "idle":
lines = lines + [when + " idle at floor " + str(e[2])]
elif e[3] == 1:
lines = lines + [when + " up to " + str(events[j][2])]
else:
lines = lines + [when + " down to " + str(events[j][2])]
i = j + 1
return lines
def trip(p):
return who(p) + " -> " + str(p[2])
def building(state):
f = lift.highest
while f >= lift.lowest:
car = " "
if state[1] == f:
n = str(len(state[4]))
if len(n) < 2:
n = " " + n
car = "[" + n + "]"
calls = ""
for p in state[3]:
if p[1] == f:
if calls != "":
calls = calls + ", "
calls = calls + trip(p)
line = " " + str(f) + " |" + car + "|"
if calls != "":
line = line + " " + calls
print(line)
f = f - 1
line = "t=" + str(state[0]) + ": the lift is at floor " + str(state[1]) + ", " + going(state[2])
if len(state[4]) == 0:
line = line + ", empty."
else:
riders = ""
for p in state[4]:
if riders != "":
riders = riders + ", "
riders = riders + trip(p)
line = line + ", with " + riders + "."
print(line)
def longest(ps, k, j):
best = -1
whose = []
for p in ps:
v = p[j] - p[k]
if v > best or v == best and p[0] < whose[0]:
best = v
whose = p
return [best, whose]
def total(ps, k, j):
s = 0
for p in ps:
s = s + p[j] - p[k]
return s
def statistics(state):
arrived = state[5]
picked = arrived + state[4]
calls = len(arrived) + len(state[4]) + len(state[3])
if calls == 0:
print("Nobody has called the lift yet.")
return 0
print("Calls: " + str(calls) + ". Arrived " + str(len(arrived)) + ", riding " + str(len(state[4])) + ", waiting " + str(len(state[3])) + ".")
if len(picked) == 0:
print("Nobody has been picked up yet.")
else:
w = longest(picked, 3, 4)
print("Wait for the lift: average " + average(total(picked, 3, 4), len(picked)) + ", longest " + str(w[0]) + " (" + who(w[1]) + "), over the " + str(len(picked)) + " picked up.")
if len(arrived) > 0:
a = longest(arrived, 3, 5)
print("Call to arrival: average " + average(total(arrived, 3, 5), len(arrived)) + ", longest " + str(a[0]) + " (" + who(a[1]) + "), over the " + str(len(arrived)) + " arrived.")
for p in state[3]:
print(who(p) + " has waited " + str(state[0] - p[3]) + " so far at floor " + str(p[1]) + ".")
return 0
def right(s, width):
while len(s) < width:
s = " " + s
return s
def row(label, final):
ps = final[5]
last = 0
for p in ps:
if p[5] > last:
last = p[5]
print(label + right(average(total(ps, 3, 4), len(ps)), 14) + right(str(longest(ps, 3, 4)[0]), 14) + right(average(total(ps, 3, 5), len(ps)), 14) + right("t=" + str(last), 14))
def compare(calls):
if len(calls) == 0:
print("Nobody has called the lift yet.")
return 0
what = "call"
if len(calls) > 1:
what = "calls"
print("The " + str(len(calls)) + " " + what + " again from t=0 (trip = from the call to arrival):")
print(" average wait longest wait average trip last arrival")
row(" direction rule", lift.run_all(calls, False))
row(" one at a time ", lift.run_all(calls, True))
return 0