from collections import deque
from itertools import dropwhile, islice, takewhile
from textwrap import wrap
from typing import Iterable, Iterator


Digits = str  


def esthetic_nums(base: int) -> Iterator[int]:
    
    queue: deque[tuple[int, int]] = deque()
    queue.extendleft((d, d) for d in range(1, base))
    while True:
        num, lsd = queue.pop()
        yield num
        new_lsds = (d for d in (lsd - 1, lsd + 1) if 0 <= d < base)
        num *= base  
        queue.extendleft((num + d, d) for d in new_lsds)


def to_digits(num: int, base: int) -> Digits:
    
    digits: list[str] = []
    while num:
        num, d = divmod(num, base)
        digits.append([d])
    return .join(reversed(digits)) if digits else 


def pprint_it(it: Iterable[str], indent: int = 4, width: int = 80) -> None:
    
    joined = .join(it)
    lines = wrap(joined, width=width - indent)
    for line in lines:
        print(f)
    print()


def task_2() -> None:
    nums: Iterator[int]
    for base in range(2, 16 + 1):
        start, stop = 4 * base, 6 * base
        nums = esthetic_nums(base)
        nums = islice(nums, start - 1, stop)  
        print(
            f
            f
        )
        pprint_it(to_digits(num, base) for num in nums)


def task_3(lower: int, upper: int, base: int = 10) -> None:
    nums: Iterator[int] = esthetic_nums(base)
    nums = dropwhile(lambda num: num < lower, nums)
    nums = takewhile(lambda num: num <= upper, nums)
    print(
        f
        f
    )
    pprint_it(to_digits(num, base) for num in nums)


if __name__ == :
    print()
    task_2()

    print()
    task_3(1_000, 9_999)

    print()
    task_3(100_000_000, 130_000_000)