Prep Advent of Code 2023
This commit is contained in:
parent
bad86889d6
commit
661f18dca4
4 changed files with 249 additions and 0 deletions
2
2023-python/.gitignore
vendored
Normal file
2
2023-python/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
input
|
||||||
38
2023-python/README.md
Normal file
38
2023-python/README.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
Advent of Code 2023
|
||||||
|
===================
|
||||||
|
|
||||||
|
Solutions for #aoc2023 in Python 3 (3.11.5).
|
||||||
|
|
||||||
|
Help scripts
|
||||||
|
------------
|
||||||
|
|
||||||
|
Display all solved puzzles:
|
||||||
|
|
||||||
|
python aoc.py
|
||||||
|
|
||||||
|
To bootstrap a new puzzle (creates `input/<day_no>.txt` and `output/day_<day_no>.py`):
|
||||||
|
|
||||||
|
python aoc.py <day_no> <puzzle_name>
|
||||||
|
|
||||||
|
Manually copy the puzzle input from https://adventofcode.com and paste it in `input/<day_no>.txt`
|
||||||
|
to start coding.
|
||||||
|
|
||||||
|
wl-paste > input/<day_no>.txt
|
||||||
|
|
||||||
|
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):
|
||||||
|
|
||||||
|
wl-paste | 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 `wl-paste`, Mac users can instead use `pbpaste`. If you
|
||||||
|
prefer X at Linux, use `xclip -selection clipboard -o`).
|
||||||
127
2023-python/aoc.py
Normal file
127
2023-python/aoc.py
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def headline(n, title):
|
||||||
|
"""Print day number and name, followed by a ruler. Used by the answer decorator"""
|
||||||
|
print(f"\n--- Day {n}: {title} ---\n")
|
||||||
|
|
||||||
|
|
||||||
|
year = 2023
|
||||||
|
|
||||||
|
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:
|
||||||
|
name = " ".join(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 # , matrix, D, DD, ADJ, ints, mhd, mdbg, vdbg
|
||||||
|
|
||||||
|
n = {day_no}
|
||||||
|
title = "{name}"
|
||||||
|
|
||||||
|
|
||||||
|
@answer(1, "Answer is {{}}")
|
||||||
|
def part_1(presolved):
|
||||||
|
return presolved[0]
|
||||||
|
|
||||||
|
|
||||||
|
@answer(2, "Actually, answer is {{}}")
|
||||||
|
def part_2(presolved):
|
||||||
|
return presolved[1]
|
||||||
|
|
||||||
|
|
||||||
|
def solve(data):
|
||||||
|
return 1, 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# use dummy data
|
||||||
|
inp = \"\"\"
|
||||||
|
replace me
|
||||||
|
\"\"\".strip()
|
||||||
|
|
||||||
|
# uncomment to instead use stdin
|
||||||
|
# import sys; inp = sys.stdin.read().strip()
|
||||||
|
|
||||||
|
# uncomment to use AoC provided puzzle input
|
||||||
|
# with open(f"./input/{padded_no}.txt", "r") as f:
|
||||||
|
# inp = f.read()
|
||||||
|
|
||||||
|
# uncomment to do initial data processing shared by part 1-2
|
||||||
|
inp = solve(inp)
|
||||||
|
|
||||||
|
a = part_1(inp)
|
||||||
|
# b = part_2(inp)
|
||||||
|
|
||||||
|
# uncomment and replace 0 with actual output to refactor code
|
||||||
|
# and ensure nonbreaking changes
|
||||||
|
# assert a == 0
|
||||||
|
# assert b == 0
|
||||||
|
""".strip()
|
||||||
|
+ "\n"
|
||||||
|
)
|
||||||
|
print("- making sure input dir exists")
|
||||||
|
if not os.path.exists("input"):
|
||||||
|
os.makedirs("input")
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
stars = 0
|
||||||
|
for i in [str(n).zfill(2) for n in range(1, 26)]:
|
||||||
|
if not day_no or day_no.zfill(2) == i:
|
||||||
|
try:
|
||||||
|
day = __import__(
|
||||||
|
"output.day_{}".format(i),
|
||||||
|
globals(),
|
||||||
|
locals(),
|
||||||
|
["n", "title", "part_1", "part_2"],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
filepath = f"./input/{str(n).zfill(2)}.txt"
|
||||||
|
with open(filepath, "r") as f:
|
||||||
|
data = f.read()
|
||||||
|
headline(day.n, day.title)
|
||||||
|
try:
|
||||||
|
data = day.presolve(data)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
data = day.solve(data)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if day.part_1(data, decorate=True):
|
||||||
|
stars += 1
|
||||||
|
if day.part_2(data, decorate=True):
|
||||||
|
stars += 1
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
if not day_no:
|
||||||
|
print(f"\nStars: {stars}")
|
||||||
|
print("".join("*" if n < stars else "•" for n in range(50)))
|
||||||
|
print("")
|
||||||
82
2023-python/output/__init__.py
Normal file
82
2023-python/output/__init__.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import functools
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Directions/Adjacents for 2D matrices, in the order UP, RIGHT, DOWN, LEFT
|
||||||
|
D = [
|
||||||
|
(-1, 0),
|
||||||
|
(0, 1),
|
||||||
|
(1, 0),
|
||||||
|
(0, -1),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Directions for 2D matrices, as a dict with keys U, R, D, L
|
||||||
|
DD = {
|
||||||
|
"U": (-1, 0),
|
||||||
|
"R": (0, 1),
|
||||||
|
"D": (1, 0),
|
||||||
|
"L": (0, -1),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adjacent relative positions including diagonals for 2D matrices, in the order NW, N, NE, W, E, SW, S, SE
|
||||||
|
ADJ = [
|
||||||
|
(-1, -1),
|
||||||
|
(-1, 0),
|
||||||
|
(1, -1),
|
||||||
|
(0, -1),
|
||||||
|
(0, 1),
|
||||||
|
(1, 1),
|
||||||
|
(1, 0),
|
||||||
|
(1, -1),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def answer(part_index, fmt_string):
|
||||||
|
"""Decorator to present a solution in a human readable format"""
|
||||||
|
|
||||||
|
def decorator_aoc(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper_aoc(*args, **kwargs):
|
||||||
|
decorate = kwargs.get("decorate", False)
|
||||||
|
if decorate:
|
||||||
|
del kwargs["decorate"]
|
||||||
|
answer = func(*args, **kwargs)
|
||||||
|
if not decorate:
|
||||||
|
print(answer)
|
||||||
|
else:
|
||||||
|
formatted = fmt_string.format(answer)
|
||||||
|
print(f" {part_index}) {formatted}")
|
||||||
|
return answer
|
||||||
|
|
||||||
|
return wrapper_aoc
|
||||||
|
|
||||||
|
return decorator_aoc
|
||||||
|
|
||||||
|
|
||||||
|
def ints(s):
|
||||||
|
"""Extract all integers from a string"""
|
||||||
|
return [int(n) for n in re.findall(r"\d+", s)]
|
||||||
|
|
||||||
|
|
||||||
|
def mhd(a, b):
|
||||||
|
"""Calculates the Manhattan distance between 2 positions in the format (y, x) or (x, y)"""
|
||||||
|
ar, ac = a
|
||||||
|
br, bc = b
|
||||||
|
return abs(ar - br) + abs(ac - bc)
|
||||||
|
|
||||||
|
|
||||||
|
def matrix(d):
|
||||||
|
"""Transform a string into an iterable matrix. Returns the matrix, row count and col count"""
|
||||||
|
m = [tuple(r) for r in d.split()]
|
||||||
|
return m, len(m), len(m[0])
|
||||||
|
|
||||||
|
|
||||||
|
def mdbg(m):
|
||||||
|
"""Print-debug a matrix"""
|
||||||
|
for r in m:
|
||||||
|
print("".join(r))
|
||||||
|
|
||||||
|
|
||||||
|
def vdbg(seen, h, w):
|
||||||
|
"""Print-debug visited positions of a matrix"""
|
||||||
|
for r in range(h):
|
||||||
|
print("".join(["#" if (r, c) in seen else "." for c in range(w)]))
|
||||||
Loading…
Add table
Reference in a new issue