#!/usr/bin/env python """This is a small class that tries to arrange a list of characters into a circle. I'm writing this to help visualize information. It's also a fun program because it works with the curses library.""" from math import sin, cos, pi from string import lowercase import curses def rotate(L, n): """Rotate a list nondestructively to the left.""" L = list(L) left = L[0:n] right = L[n:len(L)] return right + left def getDividedAngles(n): """Given n, return back a list of angles that divides the unit circle up.""" unit = (2 * pi) / n return [unit * i for i in range(n)] def getCartesianCoords(r, theta): """Given r and theta, return back the (x,y) coordinate.""" return (r*cos(theta), r*sin(theta)) def arrangeCircularly(L, radius): results = {} angles = getDividedAngles(len(L)) for i in range(len(L)): results[L[i]] = getCartesianCoords(radius, angles[i]) return results def _displayChars(stdscr, chars_and_coords, centerx, centery): for item in chars_and_coords.keys(): x, y = chars_and_coords[item] try: stdscr.addch(y + centery, x + centerx, ord(item)) except curses.error: pass def _displayHelp(stdscr): doc = """ ] to increase radius [ to decrease radius hjkl to shift center with vi keys q to quit """ stdscr.addstr(0, 0, doc) def _driver(stdscr): radius = 7 # yes, this is hardcoded. centery, centerx = [n / 2 for n in stdscr.getmaxyx()] ch = 'sentinel' while ch != ord('q'): # I know, I know this code is terrible. I must fix it sometime. if ch == ord(']'): radius += 1 elif ch == ord('['): radius -= 1 elif ch == ord('h'): centerx -= 1 elif ch == ord('j'): centery += 1 elif ch == ord('k'): centery -= 1 elif ch == ord('l'): centerx += 1 chars_and_coords = arrangeCircularly(lowercase[0:26], radius) chars_and_coords2 = arrangeCircularly(rotate(lowercase[0:26], 13), radius - 3) _displayChars(stdscr, chars_and_coords, centerx, centery) _displayChars(stdscr, chars_and_coords2, centerx, centery) _displayHelp(stdscr) ch = stdscr.getch() stdscr.clear() if __name__ == "__main__": curses.wrapper(_driver)