# from math import abs
from collections import defaultdict

max_num = 16
initial_nums = list(range(1, max_num + 1))
initial_nums.remove(10)

# end number -> list of steps to get here which are
#     (prev_number, operation description)

target = 7387

upper_bound = target * max_num
ops = []
for n in initial_nums:
    ops.append((lambda x, n=n: x + n, f"+{n}"))
    ops.append((lambda x, n=n: abs(x - n), f"-{n}"))
    ops.append((lambda x, n=n: x * n, f"*{n}"))
    ops.append((lambda x, n=n: x // n if x and x % n == 0 else x, f"/{n}"))
    ops.append((lambda x, n=n: x**n if x**2 < upper_bound else x, f"**{n}"))


seen = {n: [] for n in initial_nums}
recent = seen.keys()

while target not in seen:
    news = defaultdict(list)
    for n in recent:
        for op, description in ops:
            new = op(n)
            if new > upper_bound:
                continue
            if new in seen:
                continue
            news[new].append((n, description))
    seen.update(news)
    recent = sorted(news.keys())
    if not news:
        assert False

    print(f"progress: {len(seen)=}")


pickers = [
    lambda l: l[0],
    lambda l: l[len(l) // 2],
    lambda l: l[-1],
]
for picker in pickers:
    steps = [target]
    picks = []
    while prevs := seen[steps[-1]]:
        pick = picker(prevs)
        picks.append(pick)
        steps.append(pick[0])

    print(f"{steps[-1]:>3}", end=" ")
    for pick in reversed(picks):
        print(f"{pick[1]:>4}", end=" ")
    print(f" = {target}")
