This commit is contained in:
2025-11-17 00:18:45 -03:00
commit 503f4c0fa6
18 changed files with 633 additions and 0 deletions

83
aoc/run.py Normal file
View File

@@ -0,0 +1,83 @@
import importlib.util
import pathlib
from aoc import exceptions
from typing import Any, Callable
import time
_ANSI_ITALIC: str = "\x1b[3m"
_ANSI_BOLD: str = "\x1b[1m"
_ANSI_RESET: str = "\x1b[0m"
def _pprint_ns(ns: int) -> str:
if ns >= 1_000_000_000:
s = ns / 1_000_000_000
return f"{s:.2f}s"
elif ns >= 1_000_000:
ms = ns / 1_000_000
return f"{ms:.2f}ms"
elif ns >= 1_000:
us = ns / 1_000
return f"{us:.2f}µs"
else:
return f"{ns}ns"
def _pprint_result(
year: int, day: int, part: int | str, result: Any, duration_ns: int
) -> None:
part = f"{_ANSI_BOLD}{year}/{day:02}/{part}{_ANSI_RESET}"
if result is None:
solved = f"{_ANSI_ITALIC}(unsolved){_ANSI_RESET}"
print(f"{part}: {solved}")
else:
if isinstance(result, list) or isinstance(result, tuple):
result = "\n".join(str(r) for r in result)
solved = f"{_ANSI_ITALIC}(elapsed: {_pprint_ns(duration_ns)}){_ANSI_RESET}"
print(f"{part}: {solved}\n{result}")
def _run_func(
f: Callable[[str], Any], year: int, day: int, part: int | str, input_data: str
) -> None:
t_1 = time.perf_counter_ns()
result = f(input_data)
t_2 = time.perf_counter_ns()
_pprint_result(year, day, part, result, t_2 - t_1)
def run_day(year: int, day: int, input_data: str, path_base: pathlib.Path) -> None:
try:
module_path = path_base / f"year_{year}" / f"day_{day:02}.py"
spec = importlib.util.spec_from_file_location(
f"year_{year}.day_{day:02}", module_path
)
if spec is None or spec.loader is None:
raise exceptions.AocError()
solution_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(solution_module)
except (ModuleNotFoundError, exceptions.AocError) as e:
raise exceptions.AocError(
f"solution module for {year}/{day:02} not found: run 'python main.py create --year {year} {day}'"
) from e
p_1 = getattr(solution_module, "part_1", None)
p_2 = getattr(solution_module, "part_2", None)
if p_1 is not None and p_2 is not None:
_run_func(p_1, year, day, 1, input_data)
_run_func(p_2, year, day, 2, input_data)
return
p_1_2 = getattr(solution_module, "part_1_2", None)
if p_1_2 is not None:
_run_func(p_1_2, year, day, "1&2", input_data)
return
raise exceptions.AocError(
f"{year}/{day:02} must define part_1 and part_2 or part_1_2"
)