Parking lot
Run an eight-space parking lot: cars come in and go out at typed times, each exit gets a ticket that shows how its fee was worked out - free up to 10 minutes, 3.00 for the first hour, 1.00 for each half hour after, at most 15.00 per 24 hours - and each day has a report of its takings, from a text menu.
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
An eight-space parking lot run from a text menu. Cars come in and go out at times the attendant types; each car takes the lowest free space. Each exit gets a ticket that shows the stay and how its fee was worked out, and each day has a report of the cars that went out and the takings.
main.eml- the menu and its questions, the lot itself (a class with its spaces), the tickets and the day reportfees.eml- the fee rules and the lines that explain a feetext.eml- trimming, capitals, reading and writing times, stays, counts and money
There is no clock: a time is typed as HH:MM and may not be earlier than the last time typed that day, and "next day" starts the following day at 00:00, so a car can stay overnight or for days. A time is kept as minutes since day 1, 00:00, so a stay is a subtraction.
The fee rules: a stay of 10 minutes or less is free. Otherwise every full 24 hours costs the day's maximum, 15.00, and what is left costs 3.00 for the first hour (or part of it) and 1.00 for each half hour (or part of one) after that - but never more than 15.00. So 2 h 35 min costs 7.00, 12 h 40 min reaches the 15.00 maximum, and from 12:00 one day to 14:30 the next costs 15.00 for the full day and 6.00 for the 2 h 30 min after it. Money is whole cents throughout.
What is checked: a plate has 2 to 10 letters, digits or dashes (typed in any case, kept in capitals) and is not already parked; a car going out must be parked; a time is HH:MM from 00:00 to 23:59 and does not go back; a car cannot come in when the lot is full. Anything else asks again; nothing cancels.
Sessions: sessions/basic.in parks four cars and takes them out - one free after 7 minutes, one for 7.00, one that reaches the day's maximum - shows the spaces and the day's report, then lets one car stay overnight into day 2 and goes out at 21.00; sessions/bad-input.in takes a car out of an empty lot, types plates that are empty, too short, too long or have a space, times in the wrong shape, out of range or earlier than the clock, parks a car twice, takes out a car that is not there, stays exactly 10 minutes (free), fills all eight spaces, tries a ninth car, and keeps one car until 07:59 the next day - 23 h 59 min, which stops at the 15.00 maximum.
Built on the verified corpus case parking-lot-tracker (a lot as a class whose spaces are taken from the lowest free one, refusing a car when full).
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
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 7
Pick a number from 1 to 6.
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
No cars are parked.
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 5
-- day 1 --
no cars went out today
0 cars out, takings 0.00; 0 still parked
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate>
Cancelled.
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> A
A plate has 2 to 10 characters.
plate> TOO-LONG-PLATE
A plate has 2 to 10 characters.
plate> AB 12
A plate has only letters, digits and dashes.
plate> ab-12
time (HH:MM)> 8:30
Type the time as HH:MM, like 08:30, or nothing to cancel.
time (HH:MM)> 25:00
Type the time as HH:MM, like 08:30, or nothing to cancel.
time (HH:MM)> 07:60
Type the time as HH:MM, like 08:30, or nothing to cancel.
time (HH:MM)> 07:30
AB-12 parks in space 1 at day 1 07:30.
== Parking lot == day 1, 07:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> ab-12
AB-12 is already parked in space 1.
== Parking lot == day 1, 07:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> ZZ-99
No car ZZ-99 is parked here.
== Parking lot == day 1, 07:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> AB-12
time (HH:MM)> 07:00
It is already 07:30 on day 1; times only move forward.
time (HH:MM)> 07:40
AB-12 leaves space 1.
in day 1 07:30
out day 1 07:40
stay 10 min
free: 10 minutes or less
fee 0.00
== Parking lot == day 1, 07:40
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C1
time (HH:MM)> 08:00
C1 parks in space 1 at day 1 08:00.
== Parking lot == day 1, 08:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C2
time (HH:MM)> 08:00
C2 parks in space 2 at day 1 08:00.
== Parking lot == day 1, 08:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C3
time (HH:MM)> 08:05
C3 parks in space 3 at day 1 08:05.
== Parking lot == day 1, 08:05
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C4
time (HH:MM)> 08:10
C4 parks in space 4 at day 1 08:10.
== Parking lot == day 1, 08:10
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C5
time (HH:MM)> 08:15
C5 parks in space 5 at day 1 08:15.
== Parking lot == day 1, 08:15
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C6
time (HH:MM)> 08:20
C6 parks in space 6 at day 1 08:20.
== Parking lot == day 1, 08:20
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C7
time (HH:MM)> 08:25
C7 parks in space 7 at day 1 08:25.
== Parking lot == day 1, 08:25
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> C8
time (HH:MM)> 08:30
C8 parks in space 8 at day 1 08:30.
== Parking lot == day 1, 08:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
The lot is full.
== Parking lot == day 1, 08:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 1
-- spaces: 8 of 8 taken --
1 C1 in since day 1 08:00
2 C2 in since day 1 08:00
3 C3 in since day 1 08:05
4 C4 in since day 1 08:10
5 C5 in since day 1 08:15
6 C6 in since day 1 08:20
7 C7 in since day 1 08:25
8 C8 in since day 1 08:30
== Parking lot == day 1, 08:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 4
Day 2 begins; it is 00:00. 8 cars still parked.
== Parking lot == day 2, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> C1
time (HH:MM)> 07:59
C1 leaves space 1.
in day 1 08:00
out day 2 07:59
stay 23 h 59 min
first hour 3.00, then 46 half hours at 1.00: 46.00 - 15.00 at most: 15.00
fee 15.00
== Parking lot == day 2, 07:59
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> C2
time (HH:MM)>
Cancelled.
== Parking lot == day 2, 07:59
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 6
Bye.
What was typed (56 lines)
7
3
5
2
2
A
TOO-LONG-PLATE
AB 12
ab-12
8:30
25:00
07:60
07:30
2
ab-12
3
ZZ-99
3
AB-12
07:00
07:40
2
C1
08:00
2
C2
08:00
2
C3
08:05
2
C4
08:10
2
C5
08:15
2
C6
08:20
2
C7
08:25
2
C8
08:30
2
1
4
3
C1
07:59
3
C2
6
basic
interpreter: byte-equal
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 1
-- spaces: 0 of 8 taken --
1 free
2 free
3 free
4 free
5 free
6 free
7 free
8 free
== Parking lot == day 1, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> ABC-123
time (HH:MM)> 08:30
ABC-123 parks in space 1 at day 1 08:30.
== Parking lot == day 1, 08:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> XYZ-789
time (HH:MM)> 08:45
XYZ-789 parks in space 2 at day 1 08:45.
== Parking lot == day 1, 08:45
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> XYZ-789
time (HH:MM)> 08:52
XYZ-789 leaves space 2.
in day 1 08:45
out day 1 08:52
stay 7 min
free: 10 minutes or less
fee 0.00
== Parking lot == day 1, 08:52
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> KLM-456
time (HH:MM)> 09:00
KLM-456 parks in space 2 at day 1 09:00.
== Parking lot == day 1, 09:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> ABC-123
time (HH:MM)> 11:05
ABC-123 leaves space 1.
in day 1 08:30
out day 1 11:05
stay 2 h 35 min
first hour 3.00, then 4 half hours at 1.00: 4.00
fee 7.00
== Parking lot == day 1, 11:05
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 2
plate> def-321
time (HH:MM)> 12:00
DEF-321 parks in space 1 at day 1 12:00.
== Parking lot == day 1, 12:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 1
-- spaces: 2 of 8 taken --
1 DEF-321 in since day 1 12:00
2 KLM-456 in since day 1 09:00
3 free
4 free
5 free
6 free
7 free
8 free
== Parking lot == day 1, 12:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> KLM-456
time (HH:MM)> 21:40
KLM-456 leaves space 2.
in day 1 09:00
out day 1 21:40
stay 12 h 40 min
first hour 3.00, then 24 half hours at 1.00: 24.00 - 15.00 at most: 15.00
fee 15.00
== Parking lot == day 1, 21:40
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 5
-- day 1 --
XYZ-789 day 1 08:45 - 08:52 0.00
ABC-123 day 1 08:30 - 11:05 7.00
KLM-456 day 1 09:00 - 21:40 15.00
3 cars out, takings 22.00; 1 still parked
== Parking lot == day 1, 21:40
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 4
Day 2 begins; it is 00:00. 1 car still parked.
== Parking lot == day 2, 00:00
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 3
plate> DEF-321
time (HH:MM)> 14:30
DEF-321 leaves space 1.
in day 1 12:00
out day 2 14:30
stay 1 day 2 h 30 min
1 full day at 15.00: 15.00
first hour 3.00, then 3 half hours at 1.00: 3.00
fee 21.00
== Parking lot == day 2, 14:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 5
-- day 2 --
DEF-321 day 1 12:00 - day 2 14:30 21.00
1 car out, takings 21.00; 0 still parked
== Parking lot == day 2, 14:30
1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit
choice> 6
Bye.
What was typed (30 lines)
1
2
ABC-123
08:30
2
XYZ-789
08:45
3
XYZ-789
08:52
2
KLM-456
09:00
3
ABC-123
11:05
2
def-321
12:00
1
3
KLM-456
21:40
5
4
3
DEF-321
14:30
5
6
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# P018 parking lot: an eight-space lot. Cars come in and go out at times the
# attendant types; the clock only moves forward, and "next day" starts the
# following day at 00:00, so a car can stay overnight or longer. Each exit
# gets a ticket showing how its fee was worked out, and each day has a report
# of its takings. A time is kept as minutes since day 1, 00:00.
import fees
import text
8 => space_count
class ParkingLot:
# Spaces numbered from 1; each holds None or [plate, time in].
def __init__(self, size):
[] => self.spaces
for i in [1:size]:
self.spaces + [None] => self.spaces
def free_space(self):
# The lowest free space number, or 0 if the lot is full.
for i in [0:len(self.spaces) - 1]:
if self.spaces[i] == None:
return i + 1
return 0
def find(self, plate):
# The space number of plate, or 0 if it is not parked here.
for i in [0:len(self.spaces) - 1]:
if self.spaces[i] != None and self.spaces[i][0] == plate:
return i + 1
return 0
def taken(self):
0 => n
for s in self.spaces:
if s != None:
n + 1 => n
return n
def park(self, plate, t):
self.free_space() => n
if n == 0:
raise ValueError("the lot is full")
[plate, t] => self.spaces[n - 1]
return n
def leave(self, n):
self.spaces[n - 1] => car
None => self.spaces[n - 1]
return car
def day_of(t):
return int((t - t % 1440) / 1440) + 1
def stamp(t):
return "day " + str(day_of(t)) + " " + text.clock(t % 1440)
def ask_plate():
# A plate in capitals, asked again until a good one is typed; "" cancels.
while True:
text.upper(text.trim(input("plate> "))) => plate
if plate == "":
return ""
True => good
for c in plate:
if not (c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"):
False => good
if len(plate) < 2 or len(plate) > 10:
"A plate has 2 to 10 characters." ^0
elif not good:
"A plate has only letters, digits and dashes." ^0
else:
return plate
def ask_time(now):
# A time today, not before now, as minutes since day 1; -1 cancels.
while True:
text.trim(input("time (HH:MM)> ")) => answer
if answer == "":
return 0 - 1
text.parse_time(answer) => m
(day_of(now) - 1) * 1440 + m => t
if m == 0 - 1:
"Type the time as HH:MM, like 08:30, or nothing to cancel." ^0
elif t < now:
("It is already " + text.clock(now % 1440) + " on day " + str(day_of(now)) + "; times only move forward.") ^0
else:
return t
ParkingLot(space_count) => lot
0 => now
[] => log
True => running
while running:
"" ^0
("== Parking lot == day " + str(day_of(now)) + ", " + text.clock(now % 1440)) ^0
"1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit" ^0
text.trim(input("choice> ")) => choice
if choice == "1":
"" ^0
("-- spaces: " + str(lot.taken()) + " of " + str(space_count) + " taken --") ^0
for i in [0:space_count - 1]:
lot.spaces[i] => car
if car == None:
(" " + ("%2d" % (i + 1)) + " free") ^0
else:
(" " + ("%2d" % (i + 1)) + " " + ("%-12s" % car[0]) + "in since " + stamp(car[1])) ^0
elif choice == "2":
if lot.free_space() == 0:
"The lot is full." ^0
else:
ask_plate() => plate
0 - 1 => t
if plate != "" and lot.find(plate) > 0:
(plate + " is already parked in space " + str(lot.find(plate)) + ".") ^0
else:
if plate != "":
ask_time(now) => t
if t == 0 - 1:
"Cancelled." ^0
else:
t => now
lot.park(plate, t) => n
(plate + " parks in space " + str(n) + " at " + stamp(t) + ".") ^0
elif choice == "3":
if lot.taken() == 0:
"No cars are parked." ^0
else:
ask_plate() => plate
0 - 1 => t
if plate != "" and lot.find(plate) == 0:
("No car " + plate + " is parked here.") ^0
else:
if plate != "":
ask_time(now) => t
if t == 0 - 1:
"Cancelled." ^0
else:
t => now
lot.find(plate) => n
lot.leave(n) => car
t - car[1] => minutes
fees.fee(minutes) => cents
log + [[plate, n, car[1], t, cents]] => log
"" ^0
(plate + " leaves space " + str(n) + ".") ^0
(" in " + stamp(car[1])) ^0
(" out " + stamp(t)) ^0
(" stay " + text.duration(minutes)) ^0
for line in fees.explain(minutes):
(" " + line) ^0
(" fee " + text.money(cents)) ^0
elif choice == "4":
day_of(now) * 1440 => now
("Day " + str(day_of(now)) + " begins; it is 00:00. " + text.count(lot.taken(), "car") + " still parked.") ^0
elif choice == "5":
0 => takings
"" ^0
("-- day " + str(day_of(now)) + " --") ^0
0 => outs
for e in log:
if day_of(e[3]) == day_of(now):
outs + 1 => outs
takings + e[4] => takings
text.clock(e[3] % 1440) => out_time
if day_of(e[2]) != day_of(e[3]):
stamp(e[3]) => out_time
(" " + ("%-12s" % e[0]) + ("%-28s" % (stamp(e[2]) + " - " + out_time)) + ("%8s" % text.money(e[4]))) ^0
if outs == 0:
" no cars went out today" ^0
(" " + text.count(outs, "car") + " out, takings " + text.money(takings) + "; " + str(lot.taken()) + " still parked") ^0
elif choice == "6":
False => running
else:
"Pick a number from 1 to 6." ^0
"Bye." ^0
Python projection (main.py)
import fees
import text
space_count = 8
class ParkingLot:
def __init__(self, size):
self.spaces = []
for i in range(1, size+1):
self.spaces = self.spaces + [None]
def free_space(self):
for i in range(0, len(self.spaces)):
if self.spaces[i] == None:
return i + 1
return 0
def find(self, plate):
for i in range(0, len(self.spaces)):
if self.spaces[i] != None and self.spaces[i][0] == plate:
return i + 1
return 0
def taken(self):
n = 0
for s in self.spaces:
if s != None:
n = n + 1
return n
def park(self, plate, t):
n = self.free_space()
if n == 0:
raise ValueError("the lot is full")
self.spaces[n - 1] = [plate, t]
return n
def leave(self, n):
car = self.spaces[n - 1]
self.spaces[n - 1] = None
return car
def day_of(t):
return int((t - t % 1440) / 1440) + 1
def stamp(t):
return "day " + str(day_of(t)) + " " + text.clock(t % 1440)
def ask_plate():
while True:
plate = text.upper(text.trim(input("plate> ")))
if plate == "":
return ""
good = True
for c in plate:
if not c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-":
good = False
if len(plate) < 2 or len(plate) > 10:
print("A plate has 2 to 10 characters.")
elif not good:
print("A plate has only letters, digits and dashes.")
else:
return plate
def ask_time(now):
while True:
answer = text.trim(input("time (HH:MM)> "))
if answer == "":
return 0 - 1
m = text.parse_time(answer)
t = (day_of(now) - 1) * 1440 + m
if m == 0 - 1:
print("Type the time as HH:MM, like 08:30, or nothing to cancel.")
elif t < now:
print("It is already " + text.clock(now % 1440) + " on day " + str(day_of(now)) + "; times only move forward.")
else:
return t
lot = ParkingLot(space_count)
now = 0
log = []
running = True
while running:
print("")
print("== Parking lot == day " + str(day_of(now)) + ", " + text.clock(now % 1440))
print("1) spaces 2) car in 3) car out 4) next day 5) day report 6) quit")
choice = text.trim(input("choice> "))
if choice == "1":
print("")
print("-- spaces: " + str(lot.taken()) + " of " + str(space_count) + " taken --")
for i in range(0, space_count):
car = lot.spaces[i]
if car == None:
print(" " + "%2d" % (i + 1) + " free")
else:
print(" " + "%2d" % (i + 1) + " " + "%-12s" % car[0] + "in since " + stamp(car[1]))
elif choice == "2":
if lot.free_space() == 0:
print("The lot is full.")
else:
plate = ask_plate()
t = 0 - 1
if plate != "" and lot.find(plate) > 0:
print(plate + " is already parked in space " + str(lot.find(plate)) + ".")
else:
if plate != "":
t = ask_time(now)
if t == 0 - 1:
print("Cancelled.")
else:
now = t
n = lot.park(plate, t)
print(plate + " parks in space " + str(n) + " at " + stamp(t) + ".")
elif choice == "3":
if lot.taken() == 0:
print("No cars are parked.")
else:
plate = ask_plate()
t = 0 - 1
if plate != "" and lot.find(plate) == 0:
print("No car " + plate + " is parked here.")
else:
if plate != "":
t = ask_time(now)
if t == 0 - 1:
print("Cancelled.")
else:
now = t
n = lot.find(plate)
car = lot.leave(n)
minutes = t - car[1]
cents = fees.fee(minutes)
log = log + [[plate, n, car[1], t, cents]]
print("")
print(plate + " leaves space " + str(n) + ".")
print(" in " + stamp(car[1]))
print(" out " + stamp(t))
print(" stay " + text.duration(minutes))
for line in fees.explain(minutes):
print(" " + line)
print(" fee " + text.money(cents))
elif choice == "4":
now = day_of(now) * 1440
print("Day " + str(day_of(now)) + " begins; it is 00:00. " + text.count(lot.taken(), "car") + " still parked.")
elif choice == "5":
takings = 0
print("")
print("-- day " + str(day_of(now)) + " --")
outs = 0
for e in log:
if day_of(e[3]) == day_of(now):
outs = outs + 1
takings = takings + e[4]
out_time = text.clock(e[3] % 1440)
if day_of(e[2]) != day_of(e[3]):
out_time = stamp(e[3])
print(" " + "%-12s" % e[0] + "%-28s" % (stamp(e[2]) + " - " + out_time) + "%8s" % text.money(e[4]))
if outs == 0:
print(" no cars went out today")
print(" " + text.count(outs, "car") + " out, takings " + text.money(takings) + "; " + str(lot.taken()) + " still parked")
elif choice == "6":
running = False
else:
print("Pick a number from 1 to 6.")
print("Bye.")
fees.eml
eml# P018 parking lot - the fee rules. A stay is a whole number of minutes and
# money is whole cents. Up to 10 minutes is free; otherwise every full 24
# hours costs the day's maximum, and what is left costs 3.00 for the first
# hour (or part of it) and 1.00 for each half hour (or part of one) after
# that, but never more than the day's maximum.
import text
10 => grace_minutes
300 => first_hour
100 => per_half_hour
1500 => day_cap
1440 => day_minutes
def part_of_day(minutes):
# The fee for less than 24 hours: [cents, half hours after the first
# hour, whether the day's maximum was reached].
if minutes == 0:
return [0, 0, False]
0 => halves
if minutes > 60:
minutes - 60 => after
int((after + 29 - (after + 29) % 30) / 30) => halves
first_hour + halves * per_half_hour => cents
if cents > day_cap:
return [day_cap, halves, True]
return [cents, halves, False]
def fee(minutes):
# The fee for a stay of minutes, in cents.
if minutes <= grace_minutes:
return 0
int((minutes - minutes % day_minutes) / day_minutes) => days
return days * day_cap + part_of_day(minutes % day_minutes)[0]
def explain(minutes):
# The lines that show how fee(minutes) was worked out.
if minutes <= grace_minutes:
return ["free: " + str(grace_minutes) + " minutes or less"]
[] => out
int((minutes - minutes % day_minutes) / day_minutes) => days
if days > 0:
out + [text.count(days, "full day") + " at " + text.money(day_cap) + ": " + text.money(days * day_cap)] => out
part_of_day(minutes % day_minutes) => p
if minutes % day_minutes > 0:
"first hour " + text.money(first_hour) => line
if p[1] > 0:
line + ", then " + text.count(p[1], "half hour") + " at " + text.money(per_half_hour) + ": " + text.money(p[1] * per_half_hour) => line
if p[2]:
line + " - " + text.money(day_cap) + " at most: " + text.money(day_cap) => line
out + [line] => out
return out
Python projection (fees.py)
import text
grace_minutes = 10
first_hour = 300
per_half_hour = 100
day_cap = 1500
day_minutes = 1440
def part_of_day(minutes):
if minutes == 0:
return [0, 0, False]
halves = 0
if minutes > 60:
after = minutes - 60
halves = int((after + 29 - (after + 29) % 30) / 30)
cents = first_hour + halves * per_half_hour
if cents > day_cap:
return [day_cap, halves, True]
return [cents, halves, False]
def fee(minutes):
if minutes <= grace_minutes:
return 0
days = int((minutes - minutes % day_minutes) / day_minutes)
return days * day_cap + part_of_day(minutes % day_minutes)[0]
def explain(minutes):
if minutes <= grace_minutes:
return ["free: " + str(grace_minutes) + " minutes or less"]
out = []
days = int((minutes - minutes % day_minutes) / day_minutes)
if days > 0:
out = out + [text.count(days, "full day") + " at " + text.money(day_cap) + ": " + text.money(days * day_cap)]
p = part_of_day(minutes % day_minutes)
if minutes % day_minutes > 0:
line = "first hour " + text.money(first_hour)
if p[1] > 0:
line = line + ", then " + text.count(p[1], "half hour") + " at " + text.money(per_half_hour) + ": " + text.money(p[1] * per_half_hour)
if p[2]:
line = line + " - " + text.money(day_cap) + " at most: " + text.money(day_cap)
out = out + [line]
return out
text.eml
eml# P018 parking lot - reading what is typed and writing times and money. The
# interpreter that checks every session does not run string methods yet, so
# the text handling is written out here.
def trim(s):
# s without the spaces at either end.
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 upper(s):
# s with a-z turned into A-Z; everything else as it was.
"abcdefghijklmnopqrstuvwxyz" => lower_letters
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" => upper_letters
"" => out
for c in s:
c => d
for i in [0:25]:
if lower_letters[i] == c:
upper_letters[i] => d
out + d => out
return out
def clock(t):
# Minutes since midnight as HH:MM.
return ("%02d" % int((t - t % 60) / 60)) + ":" + ("%02d" % (t % 60))
def parse_time(s):
# Minutes since midnight for HH:MM (00:00 to 23:59), or -1.
if len(s) != 5 or s[2] != ":":
return 0 - 1
for i in [0, 1, 3, 4]:
if not (s[i] in "0123456789"):
return 0 - 1
int(s[0:2]) => h
int(s[3:5]) => m
if h > 23 or m > 59:
return 0 - 1
return h * 60 + m
def duration(minutes):
# A stay as "2 h 35 min", "45 min" or "1 day 2 h 30 min".
int((minutes - minutes % 1440) / 1440) => days
minutes % 1440 => rest
int((rest - rest % 60) / 60) => hours
rest % 60 => mins
"" => out
if days > 0:
count(days, "day") + " " => out
if hours > 0 or days > 0:
out + str(hours) + " h " => out
return out + str(mins) + " min"
def count(n, word):
if n == 1:
return "1 " + word
return str(n) + " " + word + "s"
def money(c):
# Whole cents as 12.50.
str(c) => s
while len(s) < 3:
"0" + s => s
return s[0:len(s) - 2] + "." + s[len(s) - 2:len(s)]
Python projection (text.py)
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 upper(s):
lower_letters = "abcdefghijklmnopqrstuvwxyz"
upper_letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
out = ""
for c in s:
d = c
for i in range(0, 26):
if lower_letters[i] == c:
d = upper_letters[i]
out = out + d
return out
def clock(t):
return "%02d" % int((t - t % 60) / 60) + ":" + "%02d" % (t % 60)
def parse_time(s):
if len(s) != 5 or s[2] != ":":
return 0 - 1
for i in [0, 1, 3, 4]:
if not s[i] in "0123456789":
return 0 - 1
h = int(s[0:2])
m = int(s[3:5])
if h > 23 or m > 59:
return 0 - 1
return h * 60 + m
def duration(minutes):
days = int((minutes - minutes % 1440) / 1440)
rest = minutes % 1440
hours = int((rest - rest % 60) / 60)
mins = rest % 60
out = ""
if days > 0:
out = count(days, "day") + " "
if hours > 0 or days > 0:
out = out + str(hours) + " h "
return out + str(mins) + " min"
def count(n, word):
if n == 1:
return "1 " + word
return str(n) + " " + word + "s"
def money(c):
s = str(c)
while len(s) < 3:
s = "0" + s
return s[0:len(s) - 2] + "." + s[len(s) - 2:len(s)]