Coverage for src/countdown/digits.py: 100%

36 statements  

« prev     ^ index     » next       coverage.py v7.11.1, created at 2026-03-27 20:23 -0700

1"""Utilities for generating large digits.""" 

2 

3from importlib.resources import files 

4from itertools import zip_longest 

5 

6DIGIT_SIZES = [] 

7CHARS_BY_SIZE = {} 

8 

9 

10def paragraphs(lines): 

11 """Return groups of non-blank lines.""" 

12 group = [] 

13 for line in lines: 

14 if line.strip(): 

15 group.append(line) 

16 elif group: 

17 yield group 

18 group = [] 

19 yield group 

20 

21 

22def transpose(lines): 

23 """Transpose a list of strings (columns become rows).""" 

24 return ("".join(column) for column in zip_longest(*lines, fillvalue=" ")) 

25 

26 

27def center(text, width): 

28 """Center text so that each line will have the given width.""" 

29 return "\n".join(f"{line:^{width}}" for line in text.splitlines()) 

30 

31 

32def populate_constants(): 

33 """Populate CHARS_BY_SIZE and DIGIT_SIZES from glyphs.txt.""" 

34 lines = ( 

35 files("countdown") 

36 .joinpath("glyphs.txt") 

37 .read_text(encoding="utf-8") 

38 .splitlines() 

39 ) 

40 number_types = list(paragraphs(lines)) 

41 for group in number_types: 

42 columns = transpose(group) 

43 numbers = ["\n".join(transpose(p)) for p in paragraphs(columns)] 

44 heights = [len(n.splitlines()) for n in numbers] 

45 widths = [max(len(line) for line in n.splitlines()) for n in numbers] 

46 max_width = max(widths) 

47 [height] = set(heights) 

48 DIGIT_SIZES.append(height) 

49 chars = CHARS_BY_SIZE[height] = {} 

50 for digit, text in enumerate(numbers, start=-1): 

51 if digit == -1: 

52 colon_width = max(len(line) for line in text.splitlines()) 

53 chars[":"] = ( 

54 center(text, colon_width + 2) # 2 spaces around : 

55 if len(text) > 1 

56 else text 

57 ) 

58 else: 

59 chars[str(digit)] = center(text, max_width) 

60 DIGIT_SIZES.sort(reverse=True) 

61 

62 

63populate_constants()