diff --git a/2025-python/README.md b/2025-python/README.md new file mode 100644 index 0000000..8d20c7b --- /dev/null +++ b/2025-python/README.md @@ -0,0 +1,45 @@ +# Advent of Code 2025 + +Solutions for #aoc2025 in Python 3 (3.13.4). + +Programming setup: + +- Lenovo Thinkpad T14 +- OpenSUSE Tumbleweed with labwc +- Helix editor w/ Ruff LS +- Vivaldi +- Foot + +## Help scripts + +Display all solved puzzles: + + python aoc.py + +To bootstrap a new puzzle (creates `input/.txt` and `output/day_.py`): + + python aoc.py new + +Manually copy the puzzle input from https://adventofcode.com and paste it in `input/.txt` +to start coding. + + wl-paste > input/.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 'wlpaste | 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`). + diff --git a/2025-python/aoc.py b/2025-python/aoc.py new file mode 100644 index 0000000..d185846 --- /dev/null +++ b/2025-python/aoc.py @@ -0,0 +1,118 @@ +import sys +from pathlib import Path + + +def headline(n): + """Print day number and name, followed by a ruler. Used by the answer decorator""" + print(f"\nDay {int(n)} - https://adventofcode.com/{year}/day/{int(n)}\n") + + +year = 2025 +nostrip = [] + +try: + _, day_no, *name = sys.argv +except ValueError: + day_no = None + name = None + +Path("./input").mkdir(parents=True, exist_ok=True) +Path("./output").mkdir(parents=True, exist_ok=True) + +if day_no and name: + name = " ".join(name) + padded_no = day_no.zfill(2) + with open("output/day_{}.py".format(padded_no), "w") as s: + s.write( + f""" +import re +from collections import deque, Counter, defaultdict +from heapq import heappop, heappush +from itertools import compress, combinations, chain, permutations + +from output import matrix, D, DD, ADJ, ints, sints, mhd, mdbg, vdbg, cw, ccw, bk + + +def solve(data): + p1 = None + p2 = None + return p1, p2 + + +if __name__ == "__main__": + import os + + # 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("./input/{padded_no}.txt", "r") as f: + # inp = f.read().strip() + + # uncomment to do initial data processing shared by part 1-2 + p1, p2 = solve(inp) + + print(p1) + os.system(f"echo {{p1}} | wl-copy") + # print(p2) + # os.system(f"echo {{p2}} | wl-copy") + + # uncomment and replace 0 with actual output to refactor code + # and ensure nonbreaking changes + # assert p1 == 0 + # assert p2 == 0 +""".strip() + + "\n" + ) + exit(0) + +print( + f"\n\033[95m\033[1mAdvent of Code {year}\033[0m" + "\n###################" + "\n\n\033[96mby Anders Englöf Ytterström\033[0m" +) + + +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(), + ["solve"], + 0, + ) + with open(f"./input/{i}.txt", "r") as f: + data = f.read() + if int(i) not in nostrip: + data = data.strip() + headline(i) + try: + data = day.presolve(data) + except AttributeError: + pass + try: + p1, p2 = day.solve(data) + except AttributeError: + pass + if p1: + print(f" \033[92m1)\033[0m {p1}") + stars += 1 + if p2: + print(f" \033[92m2)\033[0m {p2}") + 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(24))) +print("") diff --git a/2025-python/output/__init__.py b/2025-python/output/__init__.py new file mode 100644 index 0000000..8c26c52 --- /dev/null +++ b/2025-python/output/__init__.py @@ -0,0 +1,257 @@ +import re +from math import inf +from PIL import Image + +# Directions/Adjacents for 2D matrices, in the order UP, RIGHT, DOWN, LEFT +D = [ + (-1, 0), + (0, 1), + (1, 0), + (0, -1), +] + +Di = [ + (-1, -1), + (-1, 1), + (1, -1), + (1, 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), +} + +DDa = { + "^": (-1, 0), + ">": (0, 1), + "v": (1, 0), + "<": (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 ints(s): + """Extract all integers from a string""" + return [int(n) for n in re.findall(r"\d+", s)] + + +def sints(s): + """Extract all signed 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 grid(d, o="#"): + """Transform a string into an iterable matrix. Returns the matrix, row count and col count""" + m = [tuple(r) for r in d.split()] + return set([(r, c) for c in range(len(m[0])) for r in range(len(m)) if m[r][c] == o]) + + +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, mask=("#", "."), M=None): + """Print-debug visited positions of a matrix""" + t = inf + l = inf + b = 0 + r = 0 + for y, x in seen: + t = min(t, y) + r = max(r, x) + b = max(b, y) + l = min(l, x) + H = b + 1 + W = r + 1 + osr = 0 #t + osc = 0 #l + C, Z = mask + def _m(r, c): + return M[r][c] if M else Z + O = [] + for r in range(H): + O.append("".join([C if (r + osr, c + osc) in seen else _m(r, c) for c in range(W)])) + print("\n".join(O)) + + +def svg(seen): + """Print-debug visited positions of a matrix""" + t = inf + l = inf + b = 0 + r = 0 + rects = [] + for y, x in seen: + t = min(t, y) + r = max(r, x) + b = max(b, y) + l = min(l, x) + H = b - t + 1 + W = r - l + 1 + print(t, r, b, l) + im = Image.new(mode="RGB", size=(W,H), color=(255,255,255)) + for y, x in seen: + im.putpixel((x-l, y-t), (0, 0, 0, 255)) + im.save("aoc.png") + + for y, x in seen: + rects.append(f"") + with open("svg.svg", "w") as f: + f.write(f""" + + {"".join(rects)} + + """.strip()) + + +def vvdbg(seen, h, w): + """Print-debug visited positions of a matrix, with values""" + for r in range(h): + print("".join([seen[(r, c)] if (r, c) in seen else "." for c in range(w)])) + + +def cw(y, x): + """Flip a (y, x) direction counterwise: U->R, R->D, D->L, L->U. + + >>> cw(-1, 0) + (0, 1) + >>> cw(0, 1) + (1, 0) + >>> cw(1, 0) + (0, -1) + >>> cw(0, -1) + (-1, 0) + """ + return (x, y) if y == 0 else (x, -y) + + +def ccw(y, x): + """Flip a (y, x) direction counterwise: U->L, L->D, D->R, R->U. + + >>> ccw(-1, 0) + (0, -1) + >>> ccw(0, -1) + (1, 0) + >>> ccw(1, 0) + (0, 1) + >>> ccw(0, 1) + (-1, 0) + """ + return (x, y) if x == 0 else (-x, y) + + +def bfs(S, E=None): + """BFS algorithm, equal weighted nodes""" + seen = set() + q = [(S, 0)] + g = {} # graph, required to be provided at some point + while q: + m, w = q.pop(0) + if m in seen: + continue + seen.add(m) + # investigate here + for s in g[m]: + q.append((s, w + 1)) + # return insights + + +def mhd_search(r, c, R=20): + """returns all coords that are within R manhattan distance from (r,c)""" + p = set() + for d in range(1, R + 1): + p.add((r, c + d)) + p.add((r, c - d)) + p.add((r + d, c)) + p.add((r - d, c)) + for dd in range(d): + p.add((r - dd, c - d + dd)) + p.add((r + dd, c - d + dd)) + p.add((r - dd, c - dd + d)) + p.add((r + dd, c - dd + d)) + return p + + +def dijkstras(grid, start, target): + """ + 1. Create an array that holds the distance of each vertex from the starting + vertex. Initially, set this distance to infinity for all vertices except + the starting vertex which should be set to 0. + 2. Create a priority queue (heap) and insert the starting vertex with its + distance of 0. + 3. While there are still vertices left in the priority queue, select the vertex + with the smallest recorded distance from the starting vertex and visit its + neighboring vertices. + 4. For each neighboring vertex, check if it is visited already or not. If it + isn’t visited yet, calculate its tentative distance by adding its weight + to the smallest distance found so far for its parent/previous node + (starting vertex in case of first-level vertices). + 5. If this tentative distance is smaller than previously recorded value + (if any), update it in our ‘distances’ array. + 6. Finally, add this visited vertex with its updated distance to our priority + queue and repeat step-3 until we have reached our destination or exhausted + all nodes. + """ + import heapq + + target = max(grid) + seen = set() + queue = [(start, 0)] + while queue: + cost, pos, direction, steps = heapq.heappop(queue) + y, x = pos + dy, dx = direction + + if pos == target: + return cost + + if ((pos, "and stuff")) in seen: + continue + + seen.add((pos, "and stuff")) + + neighbors = [] + for n in neighbors: + heapq.heappush(queue, ("stuffs")) + + return -1 + + +def bk(graph, p, r=set(), x=set()): + """Bron-Kerbosch algoritm, no pivot: https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm""" + if not p and not x: + yield r + while p: + v = p.pop() + yield from bk(graph, p & set(graph[v]), r | {v}, x & graph[v]) + x.add(v) diff --git a/2025-python/output/day_01.py b/2025-python/output/day_01.py new file mode 100644 index 0000000..a5db17e --- /dev/null +++ b/2025-python/output/day_01.py @@ -0,0 +1,29 @@ +def solve(data): + d = 50 + p1 = 0 + p2 = 0 + for s in data.split(): + sf0 = d == 0 + m, T = (-1, 99) if s[0] == "L" else (1, 1) + for _ in range(int(s[1:])): + d = (d + m) % 100 + if d == T: + if sf0: + sf0 = False + continue + p2 += 1 + p1 += d == 0 + return p1, p1 + p2 + + +if __name__ == "__main__": + with open("./input/01.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 1195 + assert p2 == 6770 diff --git a/2025-python/output/day_02.py b/2025-python/output/day_02.py new file mode 100644 index 0000000..909bb95 --- /dev/null +++ b/2025-python/output/day_02.py @@ -0,0 +1,35 @@ +import re + +from output import ints + + +def solve(data): + p1 = set() + p2 = set() + R = re.compile(r"^(\w+)\1+$") + for line in data.split(","): + a, b = ints(line) + for n in range(a, b + 1): + s = str(n) + ls = len(s) + for seq in re.findall(R, s): + sqrts = [i for i in range(1, ls + 1) if ls % i == 0] + for t in sqrts: + if "".join([seq] * t) == s: + if t == 2: + p1.add(n) + p2.add(n) + return sum(p1), sum(p2) + + +if __name__ == "__main__": + with open("./input/02.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 38437576669 + assert p2 == 49046150754 diff --git a/2025-python/output/day_03.py b/2025-python/output/day_03.py new file mode 100644 index 0000000..8d993b3 --- /dev/null +++ b/2025-python/output/day_03.py @@ -0,0 +1,31 @@ +def solve(data): + p1 = 0 + p2 = 0 + for line in data.splitlines(): + p1 += _maxj(line, 2) + p2 += _maxj(line, 12) + return p1, p2 + + +def _maxj(line, C): + toexcl = len(line) - C + batt = [] + for c in line: + while toexcl and batt and batt[-1] < c: + toexcl -= 1 + batt.pop() + batt.append(c) + return sum(10**x * int(y) for x, y in zip(range(C - 1, -1, -1), batt)) + + +if __name__ == "__main__": + with open("./input/03.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 17430 + assert p2 == 171975854269367 diff --git a/2025-python/output/day_04.py b/2025-python/output/day_04.py new file mode 100644 index 0000000..63dc903 --- /dev/null +++ b/2025-python/output/day_04.py @@ -0,0 +1,31 @@ +from output import grid, ADJ + + +def solve(data): + p1 = 0 + p2 = set() + G = grid(data, o="@") + while True: + for r, c in G: + if sum((r + dy, c + dx) in G for dy, dx in ADJ) < 4: + p2.add((r, c)) + if p1 == 0: + p1 = len(p2) + if not G & p2: + break + G = G - p2 + p2 = len(p2) + return p1, p2 + + +if __name__ == "__main__": + with open("./input/04.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 1493 + assert p2 == 9194 diff --git a/2025-python/output/day_05.py b/2025-python/output/day_05.py new file mode 100644 index 0000000..eda70e6 --- /dev/null +++ b/2025-python/output/day_05.py @@ -0,0 +1,31 @@ +from output import ints + + +def solve(data): + p1 = None + p2 = 0 + ranges, ids = data.split("\n\n") + ids = ints(ids) + R = [ints(line) for line in ranges.split()] + p1 = sum(any(s <= n <= e for s, e in R) for n in ids) + c = 0 + for s, e in sorted(R): + s = max(c + 1, s) + if s <= e: + p2 += e - s + 1 + c = max(e, c) + + return p1, p2 + + +if __name__ == "__main__": + with open("./input/05.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 509 + assert p2 == 336790092076620 diff --git a/2025-python/output/day_06.py b/2025-python/output/day_06.py new file mode 100644 index 0000000..8e396c7 --- /dev/null +++ b/2025-python/output/day_06.py @@ -0,0 +1,40 @@ +import re +from math import prod + + +def solve(data): + p1 = 0 + p2 = 0 + rows = data.splitlines() + J = max(len(r) for r in rows) + 1 + rows = [r.ljust(J) for r in rows] + ops = rows.pop() + s = 0 + for ows in re.findall(r"(\S\s+)", ops): + o, *ws = ows + e = s + len(ws) + col = [ns for ns in [r[s:e] for r in rows]] + s += len(ows) + col1 = [int(r) for r in col] + col2 = [int("".join([nsc for nsc in ns if nsc.isdigit()])) for ns in zip(*col)] + match o: + case "*": + p1 += prod(col1) + p2 += prod(col2) + case "+": + p1 += sum(col1) + p2 += sum(col2) + return p1, p2 + + +if __name__ == "__main__": + with open("./input/06.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 5524274308182 + assert p2 == 8843673199391 diff --git a/2025-python/output/day_07.py b/2025-python/output/day_07.py new file mode 100644 index 0000000..22b6c25 --- /dev/null +++ b/2025-python/output/day_07.py @@ -0,0 +1,50 @@ +import functools +from output import grid + + +def solve(data): + G = grid(data, o="^") + p1 = set() + p2 = 0 + H = len(data.split()) + W = len(data.split()[0]) + S = (0, data.split()[0].index("S")) + Q = [S] + while Q: + y, x = Q.pop(0) + if y == H: + continue + if (y, x) in p1: + continue + if (y, x) in G: + Q.append((y, x - 1)) + Q.append((y, x + 1)) + p1.add((y, x)) + else: + Q.append((y + 1, x)) + p1 = len(p1) + + @functools.cache + def _timelines(p): + y, x = p + if not 0 <= y < H or not 0 <= x < W: + return 1 + if p in G: + return _timelines((y, x - 1)) + _timelines((y, x + 1)) + return _timelines((y + 1, x)) + + p2 = _timelines(S) + return p1, p2 + + +if __name__ == "__main__": + with open("./input/07.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 1539 + assert p2 == 6479180385864 diff --git a/2025-python/output/day_08.py b/2025-python/output/day_08.py new file mode 100644 index 0000000..a1aa697 --- /dev/null +++ b/2025-python/output/day_08.py @@ -0,0 +1,58 @@ +from math import sqrt +from itertools import combinations + +from output import ints + + +def solve(data): + Di = sorted( + map(_euclidan_distance, combinations(data.splitlines(), r=2)), + key=lambda r: r[1], + ) + C = [] + S = len(data.splitlines()) + IP = 1000 + for i, pq in enumerate(Di, start=1): + pq, _ = pq + c = set(pq) + p, q = pq + rmq = [] + nothing = False + for j in C: + if p in j and q in j: + nothing = True + continue + if p in j or q in j: + c = c | j + rmq.append(j) + C = [e for e in C if e not in rmq] + if c == pq and nothing: + continue + if len(c) == S: + p2 = ints(p)[0] * ints(q)[0] + break + C = [c] + C + if i == IP: + a, b, c = sorted(list(map(len, C)), reverse=True)[:3] + p1 = a * b * c + return p1, p2 + + +def _euclidan_distance(pq): + p, q = pq + p1, p2, p3 = ints(p) + q1, q2, q3 = ints(q) + return (p, q), sqrt((p1 - q1) ** 2 + (p2 - q2) ** 2 + (p3 - q3) ** 2) + + +if __name__ == "__main__": + with open("./input/08.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 84968 + assert p2 == 8663467782 diff --git a/2025-python/output/day_09.py b/2025-python/output/day_09.py new file mode 100644 index 0000000..17434b1 --- /dev/null +++ b/2025-python/output/day_09.py @@ -0,0 +1,99 @@ +from math import inf +from itertools import combinations +from output import ints + + +def solve(data): + p1 = 0 + p2 = 0 + A = [tuple(ints(pos)) for pos in data.splitlines()] + T = inf + R = 0 + B = 0 + L = inf + for r, c in A: + T = min(r, T) + R = max(c, R) + B = max(r, B) + L = min(c, L) + S = A[0] + V = set() + W = set() + while True: + V.add(S) + W.add(S) + y, x = S + he = [(r, c) for r, c in A if r == y and (r, c) not in V] + ve = [(r, c) for r, c in A if c == x and (r, c) not in V] + if not he and not ve: + E = A[0] + elif he and ve: + E = min(min(he), min(ve)) + elif he and not ve: + E = min(he) + else: + E = min(ve) + y2, x2 = E + for r in range(min(y, y2), max(y, y2) + 1): + for c in range(min(x, x2), max(x, x2) + 1): + W.add((r, c)) + if E == A[0]: + break + S = E + V = V | W + + def _within(a, b): + y1, x1 = a + y2, x2 = b + T = min(y1, y2) + R = max(x1, x2) + B = max(y1, y2) + L = min(x1, x2) + return all([ + sum((r, L + 1) in W for r in range(T + 1, B)) % 2 == 0, + sum((r, R - 1) in W for r in range(T + 1, B)) % 2 == 0, + sum((T + 1, c) in W for c in range(L + 1, R)) % 2 == 0, + sum((B - 1, c) in W for c in range(L + 1, R)) % 2 == 0, + ]) + + S = len(list(combinations(A, r=2))) + i = 0 + for a, b in combinations(A, r=2): + i += 1 + if i % 100 == 0: + print(f"{str(i):>6} / {S}") + y1, x1 = a + y2, x2 = b + x = abs(x1 - x2) + 1 + y = abs(y1 - y2) + 1 + p1 = max(p1, x * y) + if _within(a, b): + p2 = max(p2, max(p2, x * y)) + return p1, p2 + + + + +if __name__ == "__main__": + with open("./input/09.txt", "r") as f: + inp = f.read().strip() + + in_p = """ + 7,1 +11,1 +11,7 +9,7 +9,5 +2,5 +2,3 +7,3 """.strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 50 + assert p2 == 24 + # assert p1 == 4749838800 + # assert p2 == 1624057680 diff --git a/2025-python/output/day_10.py b/2025-python/output/day_10.py new file mode 100644 index 0000000..2aee967 --- /dev/null +++ b/2025-python/output/day_10.py @@ -0,0 +1,78 @@ +import re +import functools +from math import inf +from pprint import pprint +from collections import deque, Counter, defaultdict +from heapq import heappop, heappush +from itertools import compress, combinations, chain, permutations + +from output import matrix, D, DD, ADJ, ints, sints, mhd, mdbg, vdbg, cw, ccw, bk + + +def solve(data): + r = r"^\[(.+)\] (.+) \{(.+)\}$" + p1 = 0 + + for j, line in enumerate(data.splitlines(), start=1): + il, b, j = re.findall(r, line)[0] + B = [set(ints(s)) for s in b.split()] + E = set([i for i, s in enumerate(il) if s == "#"]) + J = ints(j) + + p = 0 + L = set() + while L != E: + p += 1 + for bp in combinations(B, p): + L = set() + for b in bp: + L = L ^ b + if L == E: + break + if L == E: + break + # p = 0 + # L = [0] * len(J) + # while L != J: + # p += 1 + # for bp in combinations(B, p): + # L = set() + # for b in bp: + # L = L ^ b + # if L == E: + # break + # if L == E: + # break + p1 += p + p2 = None + return p1, p2 + + +if __name__ == "__main__": + import os + + # use dummy data + inp = """ +[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7} +[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2} +[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5} """.strip() + + # uncomment to instead use stdin + # import sys; inp = sys.stdin.read().strip() + + # uncomment to use AoC provided puzzle input + with open("./input/10.txt", "r") as f: + inp = f.read().strip() + + # uncomment to do initial data processing shared by part 1-2 + p1, p2 = solve(inp) + + print(p1) + os.system(f"echo {p1} | wl-copy") + print(p2) + os.system(f"echo {p2} | wl-copy") + + # uncomment and replace 0 with actual output to refactor code + # and ensure nonbreaking changes + # assert p1 == 0 + # assert p2 == 0 diff --git a/2025-python/output/day_11.py b/2025-python/output/day_11.py new file mode 100644 index 0000000..7f6c25f --- /dev/null +++ b/2025-python/output/day_11.py @@ -0,0 +1,33 @@ +import functools +from collections import defaultdict + + +def solve(data): + G = defaultdict(list) + for line in data.splitlines(): + f, *t = line.split() + G[f[:-1]] = t + + @functools.cache + def _traverse(k, fasttrack=True, fft=False, dac=False): + if k == "out": + return fasttrack or (fft and dac) + return sum( + _traverse(nk, fasttrack, fft or k == "fft", dac or k == "dac") + for nk in G[k] + ) + + return _traverse("you"), _traverse("svr", fasttrack=False) + + +if __name__ == "__main__": + with open("./input/11.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 649 + assert p2 == 458948453421420 diff --git a/2025-python/output/day_12.py b/2025-python/output/day_12.py new file mode 100644 index 0000000..c80a34a --- /dev/null +++ b/2025-python/output/day_12.py @@ -0,0 +1,26 @@ +from output import ints + + +def solve(data): + p1 = 0 + data = data.split("\n\n") + Q = data.pop().splitlines() + for q in Q: + W, H, *C = ints(q) + if W * H >= sum(C) * 9: + p1 += 1 + p2 = "God jul!" + return p1, p2 + + +if __name__ == "__main__": + with open("./input/12.txt", "r") as f: + inp = f.read().strip() + + p1, p2 = solve(inp) + + print(p1) + print(p2) + + assert p1 == 440 + assert p2 == "God jul!" diff --git a/leaderboard/Containerfile b/leaderboard/Containerfile index c05837c..d72ec28 100644 --- a/leaderboard/Containerfile +++ b/leaderboard/Containerfile @@ -8,7 +8,7 @@ RUN pip install waitress==3.0.2 FROM reqs AS app RUN mkdir /app/templates -COPY *.jinja2 /app/templates +COPY templates/*.jinja2 /app/templates COPY app.py app.py ENV AOC_TOKEN=