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
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-07 20:17 -0800
1"""Utilities for generating large digits."""
3from importlib.resources import files
4from itertools import zip_longest
6DIGIT_SIZES = []
7CHARS_BY_SIZE = {}
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
22def transpose(lines):
23 """Transpose a list of strings (columns become rows)."""
24 return ("".join(column) for column in zip_longest(*lines, fillvalue=" "))
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())
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)
58populate_constants()