Advertisement
Guest User

Untitled

a guest
Mar 6th, 2020
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.47 KB | None | 0 0
  1. import os
  2. import curses
  3. import math
  4.  
  5. from contextlib import contextmanager
  6.  
  7. BIT_PAD_WIDTH = 40
  8.  
  9. RED = curses.COLOR_RED
  10. BLACK = curses.COLOR_BLACK
  11. WHITE = curses.COLOR_WHITE
  12. CYAN = curses.COLOR_CYAN
  13. BLUE = curses.COLOR_BLUE
  14. GREEN = curses.COLOR_GREEN
  15. MAGENTA = curses.COLOR_MAGENTA
  16. YELLOW = curses.COLOR_YELLOW
  17.  
  18. HIGHLIGHTED_BIT_COLOR = 11
  19. NO_BIT_COLOR = 10
  20. HIGHLIGHTED_CELL_COLOR = 9
  21. HEADER_COLOR = 8
  22. BASIC_TEXT_COLOR = 7
  23.  
  24. HL_1, HL_2, HL_3, HL_4, HL_5, HL_6 = [20 + i for i in range(6)]
  25. HL_COLORS = [HL_1,HL_2,HL_3,HL_4,HL_5,HL_6]
  26.  
  27. CMD_ABD = 'abd'
  28. CMD_AB = 'ab'
  29. CMD_C = 'c'
  30. CMD_EN = 'en'
  31. CMD_ENX = 'enx'
  32. CMD_HIGHLIGHT = 'hl'
  33. CMD_FILTER = 'filt'
  34. CMD_CALC = 'calc'
  35.  
  36. BITS_TO_SHOW = 20
  37.  
  38. @contextmanager
  39. def justdoit():
  40. try:
  41. yield
  42. except:
  43. pass
  44.  
  45. # Funcions for calc
  46. def isprime(num):
  47. for i in range(2, isqrt(num)):
  48. if num % i == 0:
  49. return False
  50. return True
  51.  
  52. def isqrt(num):
  53. return int(math.sqrt(num))
  54.  
  55. def factors(num):
  56. factors = []
  57. cur_num = num
  58. i = 2
  59. irt = isqrt(num)
  60. while i < irt:
  61. if num % i == 0:
  62. factors.append(i)
  63. cur_num = cur_num // i
  64. else:
  65. i += 1
  66. return factors
  67.  
  68. EVAL_FUNCS = [isprime, isqrt, factors]
  69.  
  70.  
  71. class RecordList:
  72.  
  73. def __init__(self, height, width):
  74. self.height = height
  75. self.width = width
  76. self.indices = ['e', 'n', 'd', 'x', 'a', 'b', 'c', 'f', 'd+n', 'x+n', 'xx+e']
  77. self.filters = []
  78. self.highlights = []
  79. self.history = []
  80. self.history_index = len(self.history) - 1
  81. self.set_enx(1, 1, 1)
  82.  
  83. def gen_records(self):
  84. h2 = self.height // 2
  85. bottom = h2
  86. top = h2
  87. if self.height % 2:
  88. top += 1
  89.  
  90. cur_x = self.x - 1
  91. records = []
  92.  
  93. found = 0
  94. while(found < bottom):
  95. r = self.get_record(self.e, self.n, cur_x)
  96. if r and self._passes_filter(r):
  97. records.insert(0, r)
  98. found += 1
  99. cur_x -= 1
  100.  
  101. found = 0
  102. cur_x = self.x
  103. while(found < top):
  104. r = self.get_record(self.e, self.n, cur_x)
  105. if r and self._passes_filter(r):
  106. records.append(r)
  107. found += 1
  108. cur_x += 1
  109. self.records = records
  110. self.calc_params()
  111.  
  112. def add_filter(self, filter):
  113. for i in self.indices:
  114. locals()[i] = 1
  115. for func in EVAL_FUNCS:
  116. locals()[func.__name__] = func
  117. try:
  118. eval(filter)
  119. self.filters.append(filter)
  120. return True
  121. except:
  122. return False
  123.  
  124. def add_highlight(self, highlight):
  125. for i in self.indices:
  126. locals()[i] = 1
  127. for func in EVAL_FUNCS:
  128. locals()[func.__name__] = func
  129. try:
  130. eval(highlight)
  131. self.highlights.append(highlight)
  132. return True
  133. except:
  134. return False
  135.  
  136. def _passes_filter(self, record):
  137. for i in range(len(self.indices)):
  138. locals()[self.indices[i]] = record[i]
  139. for func in EVAL_FUNCS:
  140. locals()[func.__name__] = func
  141. for filt in self.filters:
  142. if not eval(filt):
  143. return False
  144. return True
  145.  
  146. def is_row_highlighted(self, row):
  147. record = self.records[row]
  148. for i in range(len(self.indices)):
  149. locals()[self.indices[i]] = record[i]
  150. for func in EVAL_FUNCS:
  151. locals()[func.__name__] = func
  152.  
  153. out = -1
  154. for i in range(len(self.highlights)):
  155. hl = self.highlights[i]
  156. if eval(hl):
  157. out = i
  158. return out
  159.  
  160.  
  161. def shift_index(self, amt):
  162. cur_dex = (self.height // 2)
  163. new_dex = cur_dex + amt
  164. x = self.records[new_dex][3]
  165. self.set_enx(self.e, self.n, x)
  166.  
  167. def rec_for_row(self, screen_row):
  168. return self.records[screen_row]
  169.  
  170. def __format_text(self, text, index):
  171. w = self.params[index]
  172.  
  173. if len(text) < w:
  174. text = ' '*(w-len(text)) + text
  175. else:
  176. text = text[-w:]
  177. return text
  178.  
  179. def text_header(self, index):
  180. content = str(self.indices[index])
  181. return self.__format_text(content, index)
  182.  
  183. def text_for_row(self, screen_row, index):
  184. content = str(self.rec_for_row(screen_row)[index])
  185. return self.__format_text(content, index)
  186.  
  187. def set_enx(self, e, n, x, add_history=True):
  188. self.e = e
  189. self.n = n
  190. self.x = x
  191.  
  192. if add_history:
  193. self.history = self.history[:self.history_index + 1]
  194. self.history.append([e, n, x])
  195. self.history_index = len(self.history) - 1
  196.  
  197. self.gen_records()
  198.  
  199. def go_back(self):
  200. nind = self.history_index - 1
  201. if nind > 0:
  202. e, n, x = self.history[nind]
  203. self.set_enx(e, n, x, add_history=False)
  204. self.history_index -= 1
  205.  
  206. def go_forward(self):
  207. nind = self.history_index + 1
  208. if nind < len(self.history):
  209. e, n, x = self.history[nind]
  210. self.set_enx(e, n, x, add_history=False)
  211. self.history_index += 1
  212.  
  213. def calc_params(self):
  214. max_widths = []
  215. num_elements = len(self.indices)
  216.  
  217. MIN_WIDTH = 3
  218.  
  219. for i in range(num_elements):
  220. max_len = MIN_WIDTH
  221. for rec in self.records:
  222. val = rec[i]
  223. strlen = len(str(val))
  224. if strlen > max_len:
  225. max_len = strlen + 1
  226. max_widths.append(max_len)
  227.  
  228. FILL = 1000
  229. if FILL:
  230. total = sum(max_widths)
  231. if total < self.width:
  232. for i in range(min(self.width - total, FILL * len(max_widths))):
  233. max_widths[i%len(max_widths)] += 1
  234. self.params = max_widths
  235.  
  236. def get_record(self, e, n, x):
  237. if e%2 != x%2:
  238. return
  239.  
  240. na2 = x * x + e
  241. if na2 % 2 == 1:
  242. return
  243.  
  244. na = (x * x + e) // 2
  245. if na % n > 0:
  246. return
  247.  
  248. a = na // n
  249. # e, n, x, a
  250. d = a + x
  251. b = a + 2 * (x + n)
  252.  
  253. f = 2 * d + 1 - e
  254. dn = d + n
  255. xn = x + n
  256. xxe = x * x + e
  257. c = a * b
  258. # self.indices = ['e', 'n', 'd', 'x', 'a', 'b', 'c', 'f', 'd+n', 'x+n', 'xx+e']
  259. return [e, n, d, x, a, b, c, f, dn, xn, xxe]
  260.  
  261.  
  262.  
  263.  
  264. class Console:
  265.  
  266. def __init__(self):
  267. x = os.get_terminal_size()
  268. self.width = x[0]
  269. self.height = x[1]
  270. self.set_up_curses()
  271. self.bit_index = 4 # Position of 'a' in (e, n, d, x, a, b)
  272. self.filters = []
  273.  
  274. @property
  275. def current_record(self):
  276. return self.record_list_view.records[len(self.record_list_view.records) // 2]
  277.  
  278. def set_up_curses(self):
  279. self.base_screen = curses.initscr()
  280. curses.start_color()
  281. curses.use_default_colors()
  282.  
  283. curses.curs_set(0)
  284. curses.noecho()
  285. curses.cbreak()
  286.  
  287. self.base_screen.keypad(1)
  288. self.set_up_colors()
  289.  
  290. list_view_height = self.height - 2
  291. list_view_width = self.width - BIT_PAD_WIDTH
  292.  
  293. self.record_list_view = RecordList(list_view_height, list_view_width)
  294. self.bit_pad = curses.newpad(list_view_height, BIT_PAD_WIDTH)
  295. self.record_pad = curses.newpad(list_view_height, list_view_width)
  296.  
  297. def end_screen(self):
  298. curses.nocbreak()
  299. curses.echo()
  300. self.base_screen.keypad(0)
  301. curses.endwin()
  302.  
  303. def set_up_colors(self):
  304. curses.init_pair(HIGHLIGHTED_BIT_COLOR, WHITE, WHITE)
  305. curses.init_pair(NO_BIT_COLOR, BLACK, BLACK)
  306. curses.init_pair(HIGHLIGHTED_CELL_COLOR, WHITE, CYAN)
  307. curses.init_pair(HEADER_COLOR, BLACK, MAGENTA)
  308. curses.init_pair(BASIC_TEXT_COLOR, WHITE, BLACK)
  309.  
  310. curses.init_pair(HL_1, WHITE, RED)
  311. curses.init_pair(HL_2, WHITE, BLUE)
  312. curses.init_pair(HL_3, WHITE, GREEN)
  313. curses.init_pair(HL_4, WHITE, YELLOW)
  314. curses.init_pair(HL_5, WHITE, MAGENTA)
  315. curses.init_pair(HL_6, WHITE, CYAN)
  316.  
  317. def main_loop(self):
  318.  
  319. big_shift_size = 5
  320.  
  321. while True:
  322. ch = self.base_screen.getch()
  323.  
  324. if ch == ord('j'):
  325. self.record_list_view.shift_index(1)
  326. if ch == ord('k'):
  327. self.record_list_view.shift_index(-1)
  328. if ch == ord('J'):
  329. self.record_list_view.shift_index(big_shift_size)
  330. if ch == ord('K'):
  331. self.record_list_view.shift_index(-big_shift_size)
  332. if ch == ord('h'):
  333. self.bit_index = (self.bit_index - 1) % len(self.record_list_view.indices)
  334. if ch == ord('l'):
  335. self.bit_index = (self.bit_index + 1) % len(self.record_list_view.indices)
  336. if ch == ord('p'):
  337. self.record_list_view.go_back()
  338. if ch == ord('n'):
  339. self.record_list_view.go_forward()
  340. if ch == ord('D'):
  341. self.change_d(1)
  342. if ch == ord('d'):
  343. self.change_d(-1)
  344. if ch == ord(':'):
  345. self.enter_input()
  346. if ch == ord('Q'):
  347. self.end_screen()
  348. return
  349. self.refresh_screen()
  350.  
  351. def clear_input_row(self):
  352. with justdoit():
  353. self.base_screen.addstr(self.height-1, 0, ':' + ' ' * (self.width - 1))
  354. self.refresh_screen()
  355.  
  356. def write_output_row(self, text):
  357. with justdoit():
  358. self.base_screen.addstr(self.height-2, 0, text + ' '*(self.width - len(text)))
  359. self.refresh_screen()
  360.  
  361. def change_d(self, amt):
  362. e, n, d, x, a, b = self.current_record[:6]
  363. c = a * b
  364. new_d = d + amt
  365. e = c - new_d**2
  366. x = new_d - a
  367. n = (x * x + e) // 2
  368. self.record_list_view.set_enx(e, n, x)
  369.  
  370. def cmd_success(self):
  371. self.write_output_row("Success")
  372.  
  373. def cmd_fail(self):
  374. self.write_output_row("Failure")
  375.  
  376. def enter_input(self):
  377. row = self.height - 1
  378. self.clear_input_row()
  379. cur_text = ''
  380. ch = self.base_screen.getch()
  381. while(ch != curses.KEY_ENTER or ch != 10):
  382. # For some reason backspace wasn't working for me so I use the raw value
  383. # if it isn't working for you uncomment the line with !!! and then
  384. # # start the app and type ":" (just the colon). Then BEFORE YOU PRESS ANYTHING
  385. # ELSE type the key you want to find the value for (probably BACKSPACE or ENTER)
  386. # then look for "Exception: N" and N should be the number that you put where 127 is
  387. #
  388. # raise Exception(ch) # !!!
  389.  
  390. if ch == 127 or ch == curses.KEY_BACKSPACE:
  391. cur_text = cur_text[:-1]
  392. elif ch == 10 or ch == curses.KEY_ENTER:
  393. try:
  394. message = self.accept_command(cur_text)
  395. except Exception as e:
  396. self.write_output_row(str(e))
  397. # Print message at this point
  398. return
  399. else:
  400. cur_text += chr(ch)
  401.  
  402. with justdoit():
  403. self.base_screen.addstr(row, 0, ':' + cur_text + ' ') # ' ' added for backspace function
  404.  
  405. ch = self.base_screen.getch()
  406.  
  407. def accept_command(self, text):
  408. args = text.strip().split()
  409.  
  410. command = args[0]
  411. rest = args[1:]
  412.  
  413. if command in [CMD_C, CMD_AB, CMD_ABD]:
  414. if command == CMD_C:
  415. a, b = 1, int(rest[0])
  416. else:
  417. a, b = [int(x) for x in rest[:2]]
  418.  
  419. if command == CMD_ABD:
  420. d = int(rest[2])
  421. else:
  422. d = int(math.sqrt(a*b))
  423. e = (a * b) - (d * d)
  424. x = d - a
  425. n = ((b - a) // 2) - x
  426. self.record_list_view.set_enx(e, n, x)
  427. return
  428.  
  429. if command in [CMD_EN, CMD_ENX]:
  430. e, n = [int(x) for x in rest[:2]]
  431. if command == CMD_ENX:
  432. x = int(rest[2])
  433. else:
  434. x = self.record_list_view.x
  435. while self.record_list_view.get_record(e, n, x) is None:
  436. x += 1
  437. self.record_list_view.set_enx(e, n, x)
  438.  
  439. if command == CMD_FILTER:
  440. text = ''.join(rest)
  441. if text.strip() == '-':
  442. self.record_list_view.filters.pop()
  443. return
  444. if text.strip() == '--':
  445. self.record_list_view.filters = []
  446. return
  447. success = self.record_list_view.add_filter(text)
  448. if success:
  449. self.cmd_success()
  450. else:
  451. self.cmd_fail()
  452.  
  453. if command == CMD_HIGHLIGHT:
  454. text = ''.join(rest)
  455. if text.strip() == '-':
  456. self.record_list_view.highlights.pop()
  457. return
  458. if text.strip() == '--':
  459. self.record_list_view.highlights = []
  460. return
  461. success = self.record_list_view.add_highlight(text)
  462. if success:
  463. self.cmd_success()
  464. else:
  465. self.cmd_fail()
  466.  
  467. if command == CMD_CALC:
  468. text = ''.join(rest)
  469. output = 'Error'
  470. for func in EVAL_FUNCS:
  471. locals()[func.__name__] = func
  472. output = eval(text)
  473. self.write_output_row(str(output))
  474.  
  475.  
  476. def refresh_screen(self):
  477. self.refresh_list_view()
  478. self.refresh_bit_pad()
  479.  
  480. def refresh_list_view(self):
  481. self.record_pad.clear()
  482. for row in range(self.record_list_view.height):
  483. row_str = ''
  484.  
  485. base_color = BASIC_TEXT_COLOR
  486. mods = 0
  487. if row == 0:
  488. base_color = HEADER_COLOR
  489. if row == self.record_list_view.height // 2:
  490. mods = curses.A_UNDERLINE
  491.  
  492. hl = self.record_list_view.is_row_highlighted(row)
  493. if hl != -1:
  494. base_color = HL_COLORS[hl % len(HL_COLORS)]
  495.  
  496. def get_val(index):
  497. if row == 0:
  498. return self.record_list_view.text_header(index)
  499. else:
  500. return self.record_list_view.text_for_row(row, index)
  501.  
  502. cur_col = 0
  503. for i in range(len(self.record_list_view.indices)):
  504. color = HIGHLIGHTED_CELL_COLOR if i == self.bit_index else base_color
  505. string_val = get_val(i) + '|'
  506. with justdoit():
  507. self.record_pad.addstr(row, cur_col, string_val,
  508. curses.color_pair(color) | mods)
  509. cur_col += len(string_val)
  510.  
  511. refresh_args = (0, 0, 0, 0, self.record_list_view.height, self.record_list_view.width)
  512. self.record_pad.refresh(*refresh_args)
  513.  
  514. def refresh_bit_pad(self):
  515. self.bit_pad.clear()
  516. start_val = 1 << (BIT_PAD_WIDTH - 1)
  517.  
  518. for row in range(self.record_list_view.height):
  519. if row == 0:
  520. continue
  521. checker = start_val
  522. row_val = self.record_list_view.rec_for_row(row)[self.bit_index]
  523. index = 0
  524.  
  525. hl = self.record_list_view.is_row_highlighted(row)
  526. base_color = NO_BIT_COLOR
  527. if hl != -1:
  528. base_color = HL_COLORS[hl % len(HL_COLORS)]
  529.  
  530. while checker > 0:
  531. with justdoit():
  532. if row_val & checker > 0:
  533. self.bit_pad.addch(row, index, ord('X'), curses.color_pair(HIGHLIGHTED_BIT_COLOR))
  534. else:
  535. self.bit_pad.addch(row, index, ord(' '), curses.color_pair(base_color))
  536. index += 1
  537. checker = checker >> 1
  538.  
  539. refresh_args = (0, 0, 0, self.record_list_view.width, \
  540. self.record_list_view.height, \
  541. self.record_list_view.width + BIT_PAD_WIDTH)
  542. self.bit_pad.refresh(*refresh_args)
  543.  
  544. def main():
  545. c = Console()
  546. c.main_loop()
  547.  
  548.  
  549. if __name__ == '__main__':
  550. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement