Skip to content

Instantly share code, notes, and snippets.

@lgastako
Last active August 27, 2026 05:48
Show Gist options
  • Select an option

  • Save lgastako/de57f43b660711b7a101b9a043a57302 to your computer and use it in GitHub Desktop.

Select an option

Save lgastako/de57f43b660711b7a101b9a043a57302 to your computer and use it in GitHub Desktop.
#!/usr/bin/env -S uv run --script
# The task:
#
# Receive an input formatted as hour:minute (e.g.: 12:13) and write it on the
# terminal with ASCII art in a style of a 7 segments display.
# We'll do this by wishful thinking. The basic presmise is that you assume that
# the perfect function you need is available, then if it's not, you implement
# it by wishful thinking, and keep doing this recurisvely until you get to the
# bottom where the functions you do need are available.
# In a real project we'd probably interview the stakeholders to nail down
# details of the spec, like "what does it mean to receive an input?" i.e. is it
# as an argument to the program, on stdin, do we need a webserver that accepts
# POST requests? What do we do if the input is malformed? etc.
# Since this is just an example we'll keep things simple and just assume that
# we will receive 1 or more formatted timestamps as the arguments to our
# program on the CLI.
# We start by assuming via wishful thinking that there already exists the exact
# function we need, which in this case is something like "to_segmented" that
# takes an argument in our input format and returns the ASCII art of that input
# as a 7-segment display. So we can just parse the arguments, and print the
# result of calling this function on each argument:
import sys
def main():
args = sys.argv[1:]
# print a leading blank line to balance space against the trailing
# blank lines.
print()
for arg in args:
print(to_segmented(arg))
# Print a trailing blank line after each timestamp to keep multiple
# timestamps separated
print()
# Of course that function doesn't exist, so now we have to implement it. We
# again use wishful thinking to assume/pretend that there are already functions
# that do exactly what we need, which is first, to parse the input format
# into the pieces we need to easily render the segmented display, and then
# to render those pieces.
def to_segmented(timestamp):
hours, minutes = parse_timestamp(timestamp)
return segmented_time(hours, minutes)
# Of course parse_timestamp doesn't exist, so we need to write it. Here we are
# getting to the first place where the functions we need actually do exist. We
# just need to split the string on the colon and then return the part before
# the colon as the hours and the part after as minutes. In the real world we'd
# probably have to thread more error handling throughout, but for purposes of
# this example, I'll keep it simple and just raise an exception if the input is
# not in the right format.
def parse_timestamp(timestamp):
pieces = timestamp.split(":")
if len(pieces) != 2:
raise ValueError("Expected hours and minutes separated by a colon, but got: " + timestamp)
hours, minutes = pieces
try:
int(hours)
except ValueError:
raise ValueError("Expected hours to be an int but was: " + hours)
try:
int(minutes)
except ValueError:
raise ValueError("Expected minutes to be an int but was: " + minutes)
if not 1 <= len(hours) <= 2:
raise ValueError("Hours should be one or two digits but was: " + hours)
if len(minutes) != 2:
raise ValueError("Minutes should be two digits but was: " + minutes)
return hours, minutes
# Now we need to implement the `segmented_time` function. First we'll pad the
# first digit with a space if it's a single digit, then once we have the padded
# digits for hours and minutes, we need to map them to individual segmented
# display digits (which we assume we have a function for via wishful thinking),
# then we assume via wishful thinking that we have a function to join those
# individual digits together horizontally.
def segmented_time(hours, minutes):
hours = hours.rjust(2, " ")
all_chars = hours + ":" + minutes
segmented_chars = [segmented_char(c) for c in all_chars]
return join_horizontally(segmented_chars)
# Now we need to implement the `segmented_char` function. For this function,
# the easiest thing for us would be if there was already a dictionary mapping
# all characters to their segmented versions, then we could just look them up
# and return them. So we assume that dictionary exists via wishful thinking.
# Unfortunately, since we can't reference things until we've defined them in
# python, I'll have to define the dictionary here first, but you can assume
# that temporally I would've written the function below this definition before
# writing the actual dictionary. In practice I'd probably just inline the
# dictionary lookup in the segmented_time function above, but I'm really just
# trying to drive home the nature of programming by wishful thinking here.
SEGMENTED_CHARS = {
"0": "\n".join([" *** ", "* *", "* *", "* *", "* *", "* *", " *** "]),
"1": "\n".join([" *", " *", " *", " *", " *", " *", " *"]),
"2": "\n".join([" *** ", " *", " *", "*****", "* ", "* ", "*****"]),
"3": "\n".join([" *** ", " *", " *", " *** ", " *", " *", " *** "]),
"4": "\n".join(["* *", "* *", "* *", " *** ", " *", " *", " *"]),
"5": "\n".join([" *** ", "* ", "* ", " *** ", " *", " *", " *** "]),
"6": "\n".join([" *** ", "* ", "* ", " *** ", "* *", "* *", " *** "]),
"7": "\n".join([" *** ", " *", " *", " *", " *", " *", " *"]),
"8": "\n".join([" *** ", "* *", "* *", " *** ", "* *", "* *", " *** "]),
"9": "\n".join([" *** ", "* *", "* *", " *** ", " *", " *", " *** "]),
":": "\n".join([" ", " * ", " * ", " ", " * ", " * ", " "]),
" ": "\n".join([" ", " ", " ", " ", " ", " ", " "]),
}
def segmented_char(c):
return SEGMENTED_CHARS[c]
# Now we need the join_horizontally function that takes the individual
# characters which are now rendered as multiple lines of output and joins them
# horizontally. This is, again, one of the functions where the rubber meets the
# road and we call into existing python functions to do the real work.
def join_horizontally(blocks, sep=" "):
split_blocks = [block.split("\n") for block in blocks]
line_groups = zip(*split_blocks)
return "\n".join(sep.join(line_group) for line_group in line_groups)
# At this point we'd have to go back and fill in the SEGMENTED_CHARS dictionary,
# which, in our case, already exists above. And we're done.
if __name__ == "__main__":
main()
@lgastako

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment