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

36 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-07 20:17 -0800

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 to contain the numbers in numbers.txt.""" 

34 lines = files("countdown").joinpath("numbers.txt").read_text(encoding="utf-8").splitlines() 

35 number_types = list(paragraphs(lines)) 

36 for group in number_types: 

37 columns = transpose(group) 

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

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

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

41 max_width = max(widths) 

42 [height] = set(heights) 

43 DIGIT_SIZES.append(height) 

44 chars = CHARS_BY_SIZE[height] = {} 

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

46 if digit == -1: 

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

48 chars[":"] = ( 

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

50 if len(text) > 1 

51 else text 

52 ) 

53 else: 

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

55 DIGIT_SIZES.sort(reverse=True) 

56 

57 

58populate_constants()