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

37 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-06 17:56 -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().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 print("group") 

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

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

42 max_width = max(widths) 

43 [height] = set(heights) 

44 DIGIT_SIZES.append(height) 

45 chars = CHARS_BY_SIZE[height] = {} 

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

47 if digit == -1: 

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

49 chars[":"] = ( 

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

51 if len(text) > 1 

52 else text 

53 ) 

54 else: 

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

56 DIGIT_SIZES.sort(reverse=True) 

57 

58 

59populate_constants()