Washing machine
Washing programs of timed stages run minute by minute, with pause and resume, a door that stays locked while there is water or the drum is turning, and power cuts that make the stage under way start again - the finish accounted for minute by minute.
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
Washing programs of timed stages, run minute by minute, and what can happen to a real machine along the way: - pause and resume; - a door that stays locked while it is unsafe; - power cuts, after which the stage under way starts again.
The finish is accounted for minute by minute.
main.eml- the menu, the programs, events and the run tablewasher.eml- the programs and their stages, reading events, and the minute-by-minute run
How each part works:
- A program is a list of stages, each with a fixed number of minutes, as in the corpus case
washing-machine-cycle-simulator. Cotton is fill 4, wash 40 and drain 2, then 3 rinses (fill 3, rinse 6, drain 2), then spin 10, for 89 minutes. Quick takes 31 minutes, delicate 50, and spin only 10. - Events happen at the start of their minute, in the order typed: pause, resume, open, close, cut (the power) or on.
- The door stays locked while the program runs and while there is water in the drum (from the first fill to the last drain). It also stays locked for a minute after the drum stops. The program cannot resume with the door open.
- A power cut keeps the stage but loses the minutes done in it. When the power comes back, that stage starts again, or waits paused if the machine was paused or the door is open.
- The finish is accounted for: the program's minutes, plus minutes paused, plus minutes without power, plus minutes done again after a power cut.
What is checked: menu choices 1 to 4; a program name; 1 to 16 events, each a minute from 0 to 299 and an action, in order of minutes, or none. An empty answer cancels. Events that make no sense at the time are refused with the reason, such as resume when not paused or a second cut. The run stops at minute 300.
Sessions: sessions/basic.in gives: - the four programs; - quick, straight through in 31 minutes; - quick with two pauses, the door refused and then opened, a resume refused with the door open, and a power cut in a drain, finishing at 42 = 31 + 7 + 3 + 1; - cotton with a 30-minute power cut 26 minutes into the wash: 145 = 89 + 30 + 26; - spin only.
sessions/bad-input.in gives: - menu choices 0 and x; the program lizard; a cancel; - events abc, an unknown action, minutes out of order, an odd count, minute 300, and 17 events; a cancel; - events at the wrong time, each refused with its reason, around a pause and a power cut in the fill; - a pause never resumed: not finished by minute 300.
Built on the verified corpus case washing-machine-cycle-simulator (stages with fixed times, run in order with a running total).
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== Washing machine ==
Programs of timed stages, minute by minute - with pause, a door that stays locked while it is unsafe, and power cuts.
1) programs 2) run 3) events 4) quit
choice> 0
Pick a number from 1 to 4.
1) programs 2) run 3) events 4) quit
choice> x
Pick a number from 1 to 4.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> lizard
Type cotton, quick, delicate or spin.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)>
Cancelled.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> abc
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 5 dance
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 10 pause 5 resume
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 12
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 300 pause
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 0 open 1 open 2 open 3 open 4 open 5 open 6 open 7 open 8 open 9 open 10 open 11 open 12 open 13 open 14 open 15 open 16 open
Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events>
Cancelled.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 0 resume 0 close 0 on 2 pause 3 pause 4 cut 5 cut 6 pause 7 resume 8 on 9 resume 10 resume
Events (minute and action): 0 resume, 0 close, 0 on, 2 pause, 3 pause, 4 cut, 5 cut, 6 pause, 7 resume, 8 on, 9 resume, 10 resume.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> quick
The quick program, 31 minutes.
Events (minute and action): 0 resume, 0 close, 0 on, 2 pause, 3 pause, 4 cut, 5 cut, 6 pause, 7 resume, 8 on, 9 resume, 10 resume.
minutes stage water door
0-1 fill yes locked
2-3 paused in fill yes locked
4-7 no power in fill yes locked
8 paused in fill yes locked
9-11 fill yes locked
12-23 wash yes locked
24-25 drain yes locked
26-28 rinse 1: fill yes locked
29-32 rinse 1 yes locked
33-34 rinse 1: drain yes locked
35-39 spin no locked
40 finished no locked
41 finished no closed
Minute 0, resume: not paused.
Minute 0, close: already closed.
Minute 0, on: the power is on.
Minute 2, pause: paused in fill.
Minute 3, pause: already paused.
Minute 4, cut: power off in fill: the 2 minutes done in it are lost.
Minute 5, cut: already off.
Minute 6, pause: the power is off.
Minute 7, resume: the power is off.
Minute 8, on: power back, still paused: fill will start again.
Minute 9, resume: fill starts, 3 minutes.
Minute 10, resume: not paused.
Finished at minute 40 = the program's 31 + 3 paused + 4 without power + 2 done again after a power cut.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 5 pause
Events (minute and action): 5 pause.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> delicate
The delicate program, 50 minutes.
Events (minute and action): 5 pause.
minutes stage water door
0-3 fill yes locked
4 wash yes locked
5-299 paused in wash yes locked
Minute 5, pause: paused in wash.
Not finished by minute 300.
1) programs 2) run 3) events 4) quit
choice> 4
Bye.
What was typed (29 lines)
0
x
2
lizard
2
3
abc
3
5 dance
3
10 pause 5 resume
3
12
3
300 pause
3
0 open 1 open 2 open 3 open 4 open 5 open 6 open 7 open 8 open 9 open 10 open 11 open 12 open 13 open 14 open 15 open 16 open
3
3
0 resume 0 close 0 on 2 pause 3 pause 4 cut 5 cut 6 pause 7 resume 8 on 9 resume 10 resume
2
quick
3
5 pause
2
delicate
4
basic
interpreter: byte-equal== Washing machine ==
Programs of timed stages, minute by minute - with pause, a door that stays locked while it is unsafe, and power cuts.
1) programs 2) run 3) events 4) quit
choice> 1
Programs, in minutes:
cotton 89 minutes: fill 4, wash 40, drain 2, 3 rinses (fill 3, rinse 6, drain 2 each), spin 10
quick 31 minutes: fill 3, wash 12, drain 2, 1 rinse (fill 3, rinse 4, drain 2), spin 5
delicate 50 minutes: fill 4, wash 20, drain 2, 2 rinses (fill 3, rinse 5, drain 2 each), spin 4
spin 10 minutes: spin 10
The door stays locked while the program runs, while there is water in the drum, and for a minute after the drum stops.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> quick
The quick program, 31 minutes.
No events: the program runs straight through.
minutes stage water door
0-2 fill yes locked
3-14 wash yes locked
15-16 drain yes locked
17-19 rinse 1: fill yes locked
20-23 rinse 1 yes locked
24-25 rinse 1: drain yes locked
26-30 spin no locked
31 finished no locked
32 finished no closed
Finished at minute 31, the program's 31.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 10 pause 11 open 14 resume 20 cut 23 on 36 pause 36 open 37 open 38 resume 38 close 39 resume 42 open 43 open
Events (minute and action): 10 pause, 11 open, 14 resume, 20 cut, 23 on, 36 pause, 36 open, 37 open, 38 resume, 38 close, 39 resume, 42 open, 43 open.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> quick
The quick program, 31 minutes.
Events (minute and action): 10 pause, 11 open, 14 resume, 20 cut, 23 on, 36 pause, 36 open, 37 open, 38 resume, 38 close, 39 resume, 42 open, 43 open.
minutes stage water door
0-2 fill yes locked
3-9 wash yes locked
10-13 paused in wash yes locked
14-18 wash yes locked
19 drain yes locked
20-22 no power in drain yes locked
23-24 drain yes locked
25-27 rinse 1: fill yes locked
28-31 rinse 1 yes locked
32-33 rinse 1: drain yes locked
34-35 spin no locked
36 paused in spin no locked
37 paused in spin no open
38 paused in spin no closed
39-41 spin no locked
42 finished no locked
43 finished no open
Minute 10, pause: paused in wash.
Minute 11, open: stays locked - water in the drum.
Minute 14, resume: wash goes on, 5 minutes left in it.
Minute 20, cut: power off in drain: the 1 minute done in it is lost.
Minute 23, on: power back: drain starts again.
Minute 36, pause: paused in spin.
Minute 36, open: stays locked - the drum is still turning.
Minute 37, open: the door opens.
Minute 38, resume: close the door first.
Minute 38, close: the door closes.
Minute 39, resume: spin goes on, 3 minutes left in it.
Minute 42, open: stays locked - the drum is still turning.
Minute 43, open: the door opens.
Finished at minute 42 = the program's 31 + 7 paused + 3 without power + 1 done again after a power cut.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> 30 cut 60 on
Events (minute and action): 30 cut, 60 on.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> cotton
The cotton program, 89 minutes.
Events (minute and action): 30 cut, 60 on.
minutes stage water door
0-3 fill yes locked
4-29 wash yes locked
30-59 no power in wash yes locked
60-99 wash yes locked
100-101 drain yes locked
102-104 rinse 1: fill yes locked
105-110 rinse 1 yes locked
111-112 rinse 1: drain yes locked
113-115 rinse 2: fill yes locked
116-121 rinse 2 yes locked
122-123 rinse 2: drain yes locked
124-126 rinse 3: fill yes locked
127-132 rinse 3 yes locked
133-134 rinse 3: drain yes locked
135-144 spin no locked
145 finished no locked
146 finished no closed
Minute 30, cut: power off in wash: the 26 minutes done in it are lost.
Minute 60, on: power back: wash starts again.
Finished at minute 145 = the program's 89 + 30 without power + 26 done again after a power cut.
1) programs 2) run 3) events 4) quit
choice> 3
Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.
events> none
No events.
1) programs 2) run 3) events 4) quit
choice> 2
program (cotton, quick, delicate or spin)> spin
The spin program, 10 minutes.
No events: the program runs straight through.
minutes stage water door
0-9 spin no locked
10 finished no locked
11 finished no closed
Finished at minute 10, the program's 10.
1) programs 2) run 3) events 4) quit
choice> 4
Bye.
What was typed (16 lines)
1
2
quick
3
10 pause 11 open 14 resume 20 cut 23 on 36 pause 36 open 37 open 38 resume 38 close 39 resume 42 open 43 open
2
quick
3
30 cut 60 on
2
cotton
3
none
2
spin
4
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# P098 washing machine: programs of timed stages, run minute by minute,
# with pause and resume, a door that stays locked while it is unsafe, and
# power cuts.
import washer
def plain(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 pad(s, n):
while len(s) < n:
s + " " => s
return s
def lpad(s, n):
while len(s) < n:
" " + s => s
return s
def describe(name):
washer.program(name) => p
washer.stages(p) => st
"" => line
if p[0] > 0:
"fill " + str(p[0]) + ", wash " + str(p[1]) + ", drain " + str(p[2]) + ", " => line
if p[3] == 1:
line + "1 rinse (fill " + str(p[4]) + ", rinse " + str(p[5]) + ", drain " + str(p[6]) + "), " => line
elif p[3] > 1:
line + str(p[3]) + " rinses (fill " + str(p[4]) + ", rinse " + str(p[5]) + ", drain " + str(p[6]) + " each), " => line
line + "spin " + str(p[7]) => line
(" " + pad(name, 10) + lpad(str(washer.total(st)), 3) + " minutes: " + line) ^0
def show_programs():
"Programs, in minutes:" ^0
for name in ["cotton", "quick", "delicate", "spin"]:
describe(name)
"The door stays locked while the program runs, while there is water in the drum, and for a minute after the drum stops." ^0
def show_events(events):
if len(events) == 0:
"No events: the program runs straight through." ^0
return
"" => line
for ev in events:
if line != "":
line + ", " => line
line + str(ev[0]) + " " + ev[1] => line
("Events (minute and action): " + line + ".") ^0
def run(events):
plain(input("program (cotton, quick, delicate or spin)> ")) => name
if name == "":
"Cancelled." ^0
return
washer.program(name) => p
if len(p) == 0:
"Type cotton, quick, delicate or spin." ^0
return
washer.stages(p) => st
washer.total(st) => need
washer.simulate(st, events, 300) => r
("The " + name + " program, " + washer.minutes(need) + ".") ^0
show_events(events)
(" " + pad("minutes", 10) + pad("stage", 28) + pad("water", 7) + "door") ^0
0 => first
r[0] => tl
for t in [1:len(tl)]:
if t == len(tl) or tl[t][0] != tl[first][0] or tl[t][1] != tl[first][1] or tl[t][2] != tl[first][2]:
" " => span
if t - 1 > first:
"-" + pad(str(t - 1), 4) => span
"no" => water
if tl[first][1]:
"yes" => water
(" " + lpad(str(first), 3) + span + " " + pad(tl[first][0], 28) + pad(water, 7) + tl[first][2]) ^0
t => first
for n in r[1]:
("Minute " + str(n[0]) + ", " + n[1] + ": " + n[2] + ".") ^0
if r[2] == -1:
("Not finished by minute 300.") ^0
return
"" => extra
if r[3] > 0:
extra + " + " + str(r[3]) + " paused" => extra
if r[4] > 0:
extra + " + " + str(r[4]) + " without power" => extra
if r[5] > 0:
extra + " + " + str(r[5]) + " done again after a power cut" => extra
if extra == "":
("Finished at minute " + str(r[2]) + ", the program's " + str(need) + ".") ^0
else:
("Finished at minute " + str(r[2]) + " = the program's " + str(need) + extra + ".") ^0
def set_events(events):
"Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none." ^0
plain(input("events> ")) => t
if t == "":
"Cancelled." ^0
return events
if t == "none":
"No events." ^0
return []
washer.parse_events(t) => out
if len(out) == 0:
"Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order." ^0
return events
show_events(out)
return out
[] => events
"== Washing machine ==" ^0
"Programs of timed stages, minute by minute - with pause, a door that stays locked while it is unsafe, and power cuts." ^0
True => running
while running:
"" ^0
"1) programs 2) run 3) events 4) quit" ^0
plain(input("choice> ")) => choice
if choice == "1":
show_programs()
elif choice == "2":
run(events)
elif choice == "3":
set_events(events) => events
elif choice == "4":
False => running
else:
"Pick a number from 1 to 4." ^0
"Bye." ^0
Python projection (main.py)
import washer
def plain(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 pad(s, n):
while len(s) < n:
s = s + " "
return s
def lpad(s, n):
while len(s) < n:
s = " " + s
return s
def describe(name):
p = washer.program(name)
st = washer.stages(p)
line = ""
if p[0] > 0:
line = "fill " + str(p[0]) + ", wash " + str(p[1]) + ", drain " + str(p[2]) + ", "
if p[3] == 1:
line = line + "1 rinse (fill " + str(p[4]) + ", rinse " + str(p[5]) + ", drain " + str(p[6]) + "), "
elif p[3] > 1:
line = line + str(p[3]) + " rinses (fill " + str(p[4]) + ", rinse " + str(p[5]) + ", drain " + str(p[6]) + " each), "
line = line + "spin " + str(p[7])
print(" " + pad(name, 10) + lpad(str(washer.total(st)), 3) + " minutes: " + line)
def show_programs():
print("Programs, in minutes:")
for name in ["cotton", "quick", "delicate", "spin"]:
describe(name)
print("The door stays locked while the program runs, while there is water in the drum, and for a minute after the drum stops.")
def show_events(events):
if len(events) == 0:
print("No events: the program runs straight through.")
return
line = ""
for ev in events:
if line != "":
line = line + ", "
line = line + str(ev[0]) + " " + ev[1]
print("Events (minute and action): " + line + ".")
def run(events):
name = plain(input("program (cotton, quick, delicate or spin)> "))
if name == "":
print("Cancelled.")
return
p = washer.program(name)
if len(p) == 0:
print("Type cotton, quick, delicate or spin.")
return
st = washer.stages(p)
need = washer.total(st)
r = washer.simulate(st, events, 300)
print("The " + name + " program, " + washer.minutes(need) + ".")
show_events(events)
print(" " + pad("minutes", 10) + pad("stage", 28) + pad("water", 7) + "door")
first = 0
tl = r[0]
for t in range(1, len(tl)+1):
if t == len(tl) or tl[t][0] != tl[first][0] or tl[t][1] != tl[first][1] or tl[t][2] != tl[first][2]:
span = " "
if t - 1 > first:
span = "-" + pad(str(t - 1), 4)
water = "no"
if tl[first][1]:
water = "yes"
print(" " + lpad(str(first), 3) + span + " " + pad(tl[first][0], 28) + pad(water, 7) + tl[first][2])
first = t
for n in r[1]:
print("Minute " + str(n[0]) + ", " + n[1] + ": " + n[2] + ".")
if r[2] == -1:
print("Not finished by minute 300.")
return
extra = ""
if r[3] > 0:
extra = extra + " + " + str(r[3]) + " paused"
if r[4] > 0:
extra = extra + " + " + str(r[4]) + " without power"
if r[5] > 0:
extra = extra + " + " + str(r[5]) + " done again after a power cut"
if extra == "":
print("Finished at minute " + str(r[2]) + ", the program's " + str(need) + ".")
else:
print("Finished at minute " + str(r[2]) + " = the program's " + str(need) + extra + ".")
def set_events(events):
print("Events as minute and action, in order: pause, resume, open, close, cut (the power) or on. For example: 10 pause 12 open 14 resume. Or none.")
t = plain(input("events> "))
if t == "":
print("Cancelled.")
return events
if t == "none":
print("No events.")
return []
out = washer.parse_events(t)
if len(out) == 0:
print("Type up to 16 pairs: a minute from 0 to 299, then pause, resume, open, close, cut or on; minutes in order.")
return events
show_events(out)
return out
events = []
print("== Washing machine ==")
print("Programs of timed stages, minute by minute - with pause, a door that stays locked while it is unsafe, and power cuts.")
running = True
while running:
print("")
print("1) programs 2) run 3) events 4) quit")
choice = plain(input("choice> "))
if choice == "1":
show_programs()
elif choice == "2":
run(events)
elif choice == "3":
events = set_events(events)
elif choice == "4":
running = False
else:
print("Pick a number from 1 to 4.")
print("Bye.")
washer.eml
eml# P098 washing machine - a program as stages with fixed times, run minute
# by minute with a running total, as in the corpus case
# washing-machine-cycle-simulator; and the things that happen to a real
# machine: pause and resume, a door that stays locked while it is unsafe,
# and a power cut, after which the stage under way starts again.
def program(name):
# [fill, wash, drain, rinses, rinse fill, rinse, rinse drain, spin]
{"cotton": [4, 40, 2, 3, 3, 6, 2, 10], "quick": [3, 12, 2, 1, 3, 4, 2, 5], "delicate": [4, 20, 2, 2, 3, 5, 2, 4], "spin": [0, 0, 0, 0, 0, 0, 0, 10]} => programs
if name in programs:
return programs[name]
return []
def stages(p):
# [label, minutes, water in the drum]
[] => out
if p[0] > 0:
out + [["fill", p[0], True], ["wash", p[1], True], ["drain", p[2], True]] => out
if p[3] > 0:
for r in [1:p[3]]:
"rinse " + str(r) => n
out + [[n + ": fill", p[4], True], [n, p[5], True], [n + ": drain", p[6], True]] => out
out + [["spin", p[7], False]] => out
return out
def total(st):
0 => n
for s in st:
n + s[1] => n
return n
def minutes(n):
if n == 1:
return "1 minute"
return str(n) + " minutes"
def parse_events(text):
# "12 pause 15 resume": minute then action, minutes 0 to 299 in order,
# 1 to 16 events; [] if anything is wrong.
{"pause": 1, "resume": 1, "open": 1, "close": 1, "cut": 1, "on": 1} => actions
[] => words
"" => w
for c in text + " ":
if c == " ":
if w != "":
words + [w] => words
"" => w
else:
w + c => w
if len(words) == 0 or len(words) % 2 == 1 or len(words) > 32:
return []
[] => out
0 => i
while i < len(words):
-1 => m
if len(words[i]) <= 3:
0 => m
for c in words[i]:
if m >= 0 and c >= "0" and c <= "9":
m * 10 + int(c) => m
else:
-1 => m
if m < 0 or m > 299 or not (words[i + 1] in actions):
return []
if len(out) > 0 and m < out[len(out) - 1][0]:
return []
out + [[m, words[i + 1]]] => out
i + 2 => i
return out
def simulate(st, events, cap):
# Minute by minute. Events at a minute happen before it is counted.
# Returns [timeline, notes, finish, paused, off, lost]: timeline holds
# [label, water, door] for each minute; finish is the minute the last
# stage is done (-1 if not by `cap`); lost is the minutes done in
# stages that a power cut made start again.
0 => s
0 => done_in
"running" => status
"" => before
False => door_open
0 => stopped
-1 => finish
0 => paused
0 => off
0 => lost
[] => timeline
[] => notes
0 => e
-1 => last
if len(events) > 0:
events[len(events) - 1][0] => last
0 => m
while m < cap and (finish == -1 or m <= finish + 1 or m <= last):
while e < len(events) and events[e][0] == m:
events[e][1] => a
"" => label
if status != "done":
st[s][0] => label
"" => text
if a == "pause":
if status == "running":
"paused" => status
m => stopped
"paused in " + label => text
elif status == "paused":
"already paused" => text
elif status == "off":
"the power is off" => text
else:
"already finished" => text
elif a == "resume":
if status == "paused":
if door_open:
"close the door first" => text
else:
"running" => status
if done_in == 0:
label + " starts, " + minutes(st[s][1]) => text
else:
label + " goes on, " + minutes(st[s][1] - done_in) + " left in it" => text
elif status == "running":
"not paused" => text
elif status == "off":
"the power is off" => text
else:
"already finished" => text
elif a == "open":
if door_open:
"already open" => text
elif status == "running":
"stays locked - the program is running" => text
elif status != "done" and st[s][2]:
"stays locked - water in the drum" => text
elif m - stopped < 1:
"stays locked - the drum is still turning" => text
else:
True => door_open
"the door opens" => text
elif a == "close":
if door_open:
False => door_open
"the door closes" => text
else:
"already closed" => text
elif a == "cut":
if status == "off":
"already off" => text
elif status == "done":
"done" => before
"off" => status
"power off; the program had finished" => text
else:
status => before
if status == "running":
m => stopped
"off" => status
if done_in == 0:
"power off in " + label + ", none of it done yet" => text
elif done_in == 1:
"power off in " + label + ": the 1 minute done in it is lost" => text
else:
"power off in " + label + ": the " + minutes(done_in) + " done in it are lost" => text
lost + done_in => lost
0 => done_in
else:
if status != "off":
"the power is on" => text
elif before == "done":
"done" => status
"power back" => text
elif before == "running" and not door_open:
"running" => status
"power back: " + label + " starts again" => text
else:
"paused" => status
if before == "running":
"power back; the door is open, so it waits, paused: " + label + " will start again" => text
else:
"power back, still paused: " + label + " will start again" => text
notes + [[m, a, text]] => notes
e + 1 => e
"finished" => label
False => water
if status != "done" and not (status == "off" and before == "done"):
st[s][0] => label
st[s][2] => water
if status == "paused":
"paused in " + label => label
elif status == "off":
"no power in " + label => label
elif status == "off":
"no power, finished" => label
"closed" => door
if door_open:
"open" => door
elif status == "running" or water or m - stopped < 1:
"locked" => door
timeline + [[label, water, door]] => timeline
if status == "running":
done_in + 1 => done_in
if done_in == st[s][1]:
s + 1 => s
0 => done_in
if s == len(st):
"done" => status
m + 1 => finish
m + 1 => stopped
len(st) - 1 => s
elif finish == -1:
if status == "paused":
paused + 1 => paused
else:
off + 1 => off
m + 1 => m
return [timeline, notes, finish, paused, off, lost]
Python projection (washer.py)
def program(name):
programs = {"cotton": [4, 40, 2, 3, 3, 6, 2, 10], "quick": [3, 12, 2, 1, 3, 4, 2, 5], "delicate": [4, 20, 2, 2, 3, 5, 2, 4], "spin": [0, 0, 0, 0, 0, 0, 0, 10]}
if name in programs:
return programs[name]
return []
def stages(p):
out = []
if p[0] > 0:
out = out + [["fill", p[0], True], ["wash", p[1], True], ["drain", p[2], True]]
if p[3] > 0:
for r in range(1, p[3]+1):
n = "rinse " + str(r)
out = out + [[n + ": fill", p[4], True], [n, p[5], True], [n + ": drain", p[6], True]]
out = out + [["spin", p[7], False]]
return out
def total(st):
n = 0
for s in st:
n = n + s[1]
return n
def minutes(n):
if n == 1:
return "1 minute"
return str(n) + " minutes"
def parse_events(text):
actions = {"pause": 1, "resume": 1, "open": 1, "close": 1, "cut": 1, "on": 1}
words = []
w = ""
for c in text + " ":
if c == " ":
if w != "":
words = words + [w]
w = ""
else:
w = w + c
if len(words) == 0 or len(words) % 2 == 1 or len(words) > 32:
return []
out = []
i = 0
while i < len(words):
m = -1
if len(words[i]) <= 3:
m = 0
for c in words[i]:
if m >= 0 and c >= "0" and c <= "9":
m = m * 10 + int(c)
else:
m = -1
if m < 0 or m > 299 or not words[i + 1] in actions:
return []
if len(out) > 0 and m < out[len(out) - 1][0]:
return []
out = out + [[m, words[i + 1]]]
i = i + 2
return out
def simulate(st, events, cap):
s = 0
done_in = 0
status = "running"
before = ""
door_open = False
stopped = 0
finish = -1
paused = 0
off = 0
lost = 0
timeline = []
notes = []
e = 0
last = -1
if len(events) > 0:
last = events[len(events) - 1][0]
m = 0
while m < cap and (finish == -1 or m <= finish + 1 or m <= last):
while e < len(events) and events[e][0] == m:
a = events[e][1]
label = ""
if status != "done":
label = st[s][0]
text = ""
if a == "pause":
if status == "running":
status = "paused"
stopped = m
text = "paused in " + label
elif status == "paused":
text = "already paused"
elif status == "off":
text = "the power is off"
else:
text = "already finished"
elif a == "resume":
if status == "paused":
if door_open:
text = "close the door first"
else:
status = "running"
if done_in == 0:
text = label + " starts, " + minutes(st[s][1])
else:
text = label + " goes on, " + minutes(st[s][1] - done_in) + " left in it"
elif status == "running":
text = "not paused"
elif status == "off":
text = "the power is off"
else:
text = "already finished"
elif a == "open":
if door_open:
text = "already open"
elif status == "running":
text = "stays locked - the program is running"
elif status != "done" and st[s][2]:
text = "stays locked - water in the drum"
elif m - stopped < 1:
text = "stays locked - the drum is still turning"
else:
door_open = True
text = "the door opens"
elif a == "close":
if door_open:
door_open = False
text = "the door closes"
else:
text = "already closed"
elif a == "cut":
if status == "off":
text = "already off"
elif status == "done":
before = "done"
status = "off"
text = "power off; the program had finished"
else:
before = status
if status == "running":
stopped = m
status = "off"
if done_in == 0:
text = "power off in " + label + ", none of it done yet"
elif done_in == 1:
text = "power off in " + label + ": the 1 minute done in it is lost"
else:
text = "power off in " + label + ": the " + minutes(done_in) + " done in it are lost"
lost = lost + done_in
done_in = 0
elif status != "off":
text = "the power is on"
elif before == "done":
status = "done"
text = "power back"
elif before == "running" and not door_open:
status = "running"
text = "power back: " + label + " starts again"
else:
status = "paused"
if before == "running":
text = "power back; the door is open, so it waits, paused: " + label + " will start again"
else:
text = "power back, still paused: " + label + " will start again"
notes = notes + [[m, a, text]]
e = e + 1
label = "finished"
water = False
if status != "done" and not (status == "off" and before == "done"):
label = st[s][0]
water = st[s][2]
if status == "paused":
label = "paused in " + label
elif status == "off":
label = "no power in " + label
elif status == "off":
label = "no power, finished"
door = "closed"
if door_open:
door = "open"
elif status == "running" or water or m - stopped < 1:
door = "locked"
timeline = timeline + [[label, water, door]]
if status == "running":
done_in = done_in + 1
if done_in == st[s][1]:
s = s + 1
done_in = 0
if s == len(st):
status = "done"
finish = m + 1
stopped = m + 1
s = len(st) - 1
elif finish == -1:
if status == "paused":
paused = paused + 1
else:
off = off + 1
m = m + 1
return [timeline, notes, finish, paused, off, lost]