Compare commits
No commits in common. "383dfa9e7a1a7d0c0e6665251b088d6d62630b68" and "81c4073f32053644800834932162580f194d92c8" have entirely different histories.
383dfa9e7a
...
81c4073f32
4 changed files with 0 additions and 393 deletions
|
|
@ -1,45 +0,0 @@
|
||||||
# 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/<day_no>.txt` and `output/day_<day_no>.py`):
|
|
||||||
|
|
||||||
python aoc.py <day_no> new
|
|
||||||
|
|
||||||
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 '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`).
|
|
||||||
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
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(50)))
|
|
||||||
print("")
|
|
||||||
|
|
@ -1,201 +0,0 @@
|
||||||
import re
|
|
||||||
|
|
||||||
# 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 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)]))
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
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
|
|
||||||
Loading…
Add table
Reference in a new issue