Created
April 2, 2020 16:16
-
-
Save salt-die/7fbaca311f8a5b1dcea18fe08bd51917 to your computer and use it in GitHub Desktop.
an analog clock for your terminal!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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