diff --git a/2019-python/.gitignore b/2019-python/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/2019-python/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/2019-python/README.md b/2019-python/README.md new file mode 100644 index 0000000..b2d6b04 --- /dev/null +++ b/2019-python/README.md @@ -0,0 +1,35 @@ +Advent of Code 2019 +=================== + +Solutions for #aoc2019 in Python 3 (3.11.5). + +Help scripts +------------ + +Display all solved puzzles: + + python aoc.py + +To bootstrap a new puzzle (creates `input/.txt` and `output/day_.py`): + + python aoc.py "" + +Manually copy the puzzle input from https://adventofcode.com and paste it in `input/.txt` +to start coding. + +Solve separate puzzle (replace `XX` with the puzzle number): + + python -m output.day_XX + +Solve separate puzzle using stdin (replace `XX` with the puzzle number): + + xclip -selection clipboard -o | python -m output.day_XX + cat tmpfile | python -m output.day_XX + +Execute separate puzzle on file save (replace `XX` with the puzzle number): + + ls output/*.py | entr -c -s 'xclip -selection clipboard -o | python -m output.day_XX' + ls output/*.py | entr -c -s 'cat tmpfile | python -m output.day_XX' + ls output/*.py | entr -c -r python -m output.day_XX + +(requires `entr` and `xclip`, Mac users can instead use `pbpaste`) diff --git a/2019-python/aoc.py b/2019-python/aoc.py new file mode 100644 index 0000000..9de0c9e --- /dev/null +++ b/2019-python/aoc.py @@ -0,0 +1,95 @@ +import sys + +year = 2019 + +try: + _, day_no, name = sys.argv +except ValueError: + day_no = None + name = None + +print( + f"\nAdvent of Code {year}" "\n###################" "\n\nby Anders Englöf Ytterström" +) + +if day_no and name: + padded_no = day_no.zfill(2) + print(f"\n- creating output/day_{padded_no}.py") + with open("output/day_{}.py".format(padded_no), "w") as s: + s.write( + f""" +from output import answer, puzzleinput + +n = {day_no} +title = "{name}" + + +@puzzleinput(n) +def parse_input(data): + return data + + +@answer(1, "Answer is {{}}") +def part_1(data): + return data + + +@answer(2, "Actually, answer is {{}}") +def part_2(data): + return data + + +if __name__ == "__main__": + # use dummy data + parsed = \"\"\" + replace me + \"\"\".strip() + + # uncomment to instead use stdin + # import fileinput + # parsed = "\\n".join(list(fileinput.input())) + + # uncomment to instead use content of input/{padded_no}.txt + # parsed = parse_input() + + part_1(parsed) + # part_2(parsed) +""".strip() + + "\n" + ) + print(f"- creating empty input/{day_no.zfill(2)}.txt") + with open("input/{}.txt".format(day_no.zfill(2)), "w") as i: + i.write("") + + print( + f""" +Done! start coding. + +Puzzle link: +https://adventofcode.com/{year}/day/{day_no} + +Puzzle input (copy and paste to input/{day_no.zfill(2)}.txt): +https://adventofcode.com/{year}/day/{day_no}/input + """ + ) + exit(0) + +from output import headline + +for i in [str(n).zfill(2) for n in range(1, 26)]: + try: + day = __import__( + "output.day_{}".format(i), + globals(), + locals(), + ["n", "title", "part_1", "part_2", "parse_input"], + 0, + ) + headline(day.n, day.title) + data = day.parse_input() + day.part_1(data, decorate=True) + day.part_2(data, decorate=True) + except IOError: + pass + except ImportError: + pass diff --git a/2019-python/output/__init__.py b/2019-python/output/__init__.py new file mode 100644 index 0000000..addf3ba --- /dev/null +++ b/2019-python/output/__init__.py @@ -0,0 +1,42 @@ +import functools + + +def puzzleinput(n, **kwargs): + filename = str(n).zfill(2) + trim_input = kwargs.get("trim_input", True) + filepath = f"./input/{filename}.txt" + + def decorator_pi(func): + @functools.wraps(func) + def wrapper_pi(*args, **kwargs): + with open(filepath, "r") as f: + data = f.read() + if trim_input: + return func(data.strip(), *args, **kwargs) + return func(data, *args, **kwargs) + + return wrapper_pi + + return decorator_pi + + +def answer(part_index, fmt_string): + def decorator_aoc(func): + @functools.wraps(func) + def wrapper_aoc(*args, **kwargs): + decorate = kwargs.get("decorate", False) + answer = func(*args) + if not decorate: + print(answer) + else: + formatted = fmt_string.format(answer) + print(f"[part {part_index}] {formatted}") + + return wrapper_aoc + + return decorator_aoc + + +def headline(n, title): + title = f"Day {n}: {title}" + print("\n".join(["", title, "".join("-" for _ in title), ""]))