Skip to content

Instantly share code, notes, and snippets.

@salt-die
Created April 2, 2020 16:16
Show Gist options
  • Save salt-die/7fbaca311f8a5b1dcea18fe08bd51917 to your computer and use it in GitHub Desktop.
Save salt-die/7fbaca311f8a5b1dcea18fe08bd51917 to your computer and use it in GitHub Desktop.
an analog clock for your terminal!
"""
An analog clock for your terminal!
The grid and base arrays in Clock are dtype=int, but this might make more sense if we just
use character arrays instead -- we may update this soon.
"""
import os
import time
import numpy as np
TERMX, _ = os.get_terminal_size()
one = [[0,0,0], [0,0,8], [0,0,8]]
two = [[0,7,0], [0,7,8], [8,7,0]]
three = [[0,7,0], [0,7,8], [0,7,8]]
four = [[0,0,0], [8,7,8], [0,0,8]]
five = [[0,7,0], [8,7,0], [0,7,8]]
six = [[0,7,0], [8,7,0], [8,7,8]]
seven = [[7,7,0], [0,0,8], [0,0,8]]
eight = [[0,7,0], [8,7,8], [8,7,8]]
nine = [[0,7,0], [8,7,8], [0,0,8]]
zero = [[0,7,0], [8,0,8], [8,7,8]]
colon = [[0,0,0], [0,6,0], [0,6,0]]
digits = [zero, one, two, three, four, five, six, seven, eight, nine]
def center(*lines):
for line in lines:
yield line.center(TERMX)
def format(part):
return [digits[int(i)] for i in f"0{part}"[-2:]]
def digital_time():
hours, minutes, seconds = map(format, time.localtime()[3:6])
return np.array([*zip(*hours, colon, *minutes, colon, *seconds)]).reshape(3, 24)
class Clock:
RADIUS = 23
CENTER = np.array((RADIUS, RADIUS))
def __init__(self):
self.grid = np.pad(np.zeros((self.RADIUS * 2, ) * 2, dtype=int), pad_width=1,
mode='constant', constant_values=1)
self.draw_face()
self.base = self.grid.copy()
def reset(self):
self.grid = self.base.copy()
def line_segment(self, angle, start, stop, value):
"""
Draw a line segment.
start, stop are between 0-1 and represent percentage of RADIUS
"""
start = start * self.RADIUS
stop = stop * self.RADIUS
angle -= np.pi / 2
angle = np.array([np.sin(angle), np.cos(angle)])
with np.errstate(divide="ignore"):
delta = abs(1 / angle)
step = 2 * np.heaviside(angle, 1) - 1
side_dis = ((step + 1) / 2) * delta
map_pos = self.CENTER.copy()
while True:
side = 0 if side_dis[0] < side_dis[1] else 1
side_dis[side] += delta[side]
map_pos[side] += step[side]
length = np.linalg.norm(map_pos - self.CENTER)
if self.grid[tuple(map_pos)] == 1 or stop <= length:
break
if start <= length:
self.grid[tuple(map_pos)] = value
def print_clock(self):
print(*center(*("".join(" #.;*._|"[value] for value in row)
for row in self.grid)), sep="\n")
def draw_face(self):
# Boundary
for theta in np.linspace(0, 2 * np.pi, 200, endpoint=False):
self.line_segment(theta, start=.95, stop=1, value=2)
i = 0
# Ticks
for theta in np.linspace(0, 2 * np.pi, 12, endpoint=False):
self.line_segment(theta, start=.8 - (0 if i % 3 else .1), stop=1, value=2)
i = i + 1
def draw_hands(self):
hours, minutes, seconds = time.localtime()[3:6]
tau = 2 * np.pi
hours = (hours + minutes / 60) % 12
for angle, stop, value in ((seconds / 60, .65, 3),
(minutes / 60, .65, 4),
(hours / 12, .4, 5)):
self.line_segment(tau * angle, 0, stop, value)
def run(self):
while True:
self.reset()
self.draw_hands()
self.grid[31:34, 11:35] = digital_time()
time.sleep(1)
os.system("clear")
self.print_clock()
if __name__=="__main__":
Clock().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment