Compare commits

...

13 commits

Author SHA1 Message Date
92df810943 Solve 2022 day 12 pt 1-2
BFS, baby.

2 things got me.

 * S position was not (0,0) in the puzzle input. Such embarrasment to
   loose time over something so stupid.
 * I asumed the elevation was fixed to to increase AND DECREASE by 1.

From the problem description:

> To avoid needing to get out your climbing gear, the elevation of the
> destination square can be at most one higher than the elevation of
> your current square; that is, if your current elevation is m, you
> could step to elevation n, but not to elevation o. _(This also means
> that the elevation of the destination square can be much lower than
> the elevation of your current square.)_

This means elevation only can _increase_ by one,
but _decrease_ with more.

So my wrong code:

0 <= abs(n - e) <= 1

got fixed with:

n - e <= 1

For pt 2, I reused the loop to find S to collect all "a" positions,
and looped them as starting points. Execution time is not the best,
but it works.
2025-11-30 19:17:15 +01:00
81c6bc4cd8 Solve 2022 Day 22 pt 1-2
This is how far I got the Dec 2022 run in Elixir.

Had no idea what so ever for pt 2, so I had to
solve it by the solutions thread in the subreddit.

At first, I wondered if circular values would be the
case. It was not.

Apparently, modular arithmetics are what I lack
knowledge about.

Not entirely sure what to call the operator, it is
either a greatest common divisor or a least common
nominator.

What it actually does is to reduce the numbers by
modulo for pt 2, which will keep them low and faster
to compute.

My math is rusty.
2025-11-30 19:17:15 +01:00
0f709f9f03 Solve 2022 dat 10 pt 1-2
Not pretty, but it works :)
2025-11-30 19:17:15 +01:00
657fe956f9 Solve 2022 day 9 pt 1-2
Pt 1 was just head and tail. For pt 2 I rewrote the
code to instead build the rope (snake) from head to
tail by always moving the head first and traverse
the body of the snake.

Yes, I think of it as a body of a snake - not knots
on a rope. Child hood memories are to damn colorful
:)

For reference, this is my visually debugging code:

def dbg(seen, snake):
    print(snake)
    for r in range(-4, 1):
        print("".join([v(r, c, snake) for c in range(0, 7)]))
    print("")

def v(r, c, snake):
    if (r,c) == snake[0]:
        return "H"
    for i, n in enumerate(snake[1:-1], start=1):
        if (r,c) == n:
            return str(i)
    if (r,c) == snake[-1]:
        return "T"
    if (r,c) == (0,0):
        return "s"
    return "."
2025-11-30 19:17:15 +01:00
179203f7be Solve 2022 day 8 pt 1-2 2025-11-30 19:17:15 +01:00
90d5ab203d Solve 2022 day 7 pt 1-2
Funny that I did not mention the problem with
recurring directory names in the first run of this
puzzle in Elixir, back in 2022 and bb708a5e58.

Most likely, the insight flew over my head that
time.

This time, I realized I could just add the size to
the size of each parent. I struggled to find a graph
traversal for it, until I realized I did not need
the graph.

The key rewrite was this:

    for p in path:
        fs[p] += size
    fs["/"] += size

... to this:

    p = "/"
    fs[p] += size
    for dir_name in path:
        p += f"/{dir_name}"
        fs[p] += size

This solved my issues for 3 hours by acknowledge that

- a directory name "a" can accour on multiple places,
  example: /a, /b/a, /c/a
- a directory name "a" can have a parent directory named
  "a", example: /a/b/a, /a/c/d/a

And as always, example input is the devil. Look at
the reak input as soon as possible.
2025-11-30 19:17:15 +01:00
a708d791c2 Solve 2022 day 6 pt 1-2 2025-11-30 19:17:15 +01:00
e800a005e8 Solve 2022 day 5 pt 1-2
Important not to strip trailing whitespace from this one :)
2025-11-30 19:17:15 +01:00
7c25aeafd7 Solve 2022 day 4 pt 1-2 2025-11-30 19:17:15 +01:00
19790f0899 Solve 2022 day 3 pt 1-2 2025-11-30 19:17:15 +01:00
597940f1b4 Solve 2022 day 2 pt 1-2 2025-11-30 19:17:15 +01:00
e791b19ab2 Solve 2022 day 1 pt 1-2 2025-11-30 19:17:15 +01:00
7b5c9c393b Inititate AOC 2022 in python 2025-11-30 19:17:15 +01:00
15 changed files with 924 additions and 0 deletions

48
2022-python/README.md Normal file
View file

@ -0,0 +1,48 @@
# Advent of Code 2022
Solutions for #aoc2022 in Python 3 (3.13.4).
Programming setup:
- Lenovo Thinkpad T14
- OpenSUSE Tumbleweed with labwc
- Helix editor
- 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`).
To lint files:
ls output/*.py | entr -r -c flake8 output --ignore=E741,E501,E203

118
2022-python/aoc.py Normal file
View file

@ -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 = 2022
nostrip = [5]
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, 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("")

View file

@ -0,0 +1,201 @@
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
isnt 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)

View file

@ -0,0 +1,26 @@
from output import ints
def solve(data):
E = data.split("\n\n")
p1 = 0
C = []
for e in E:
e = sum(ints(e))
p1 = max(p1, e)
C.append(e)
p2 = sum(sorted(C, reverse=True)[:3])
return 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 == 66616
assert p2 == 199172

View file

@ -0,0 +1,40 @@
def solve(data):
S1 = {
"A X": 1 + 3,
"A Y": 2 + 6,
"A Z": 3 + 0,
"B X": 1 + 0,
"B Y": 2 + 3,
"B Z": 3 + 6,
"C X": 1 + 6,
"C Y": 2 + 0,
"C Z": 3 + 3,
}
S2 = {
"A X": 3 + 0,
"A Y": 1 + 3,
"A Z": 2 + 6,
"B X": 1 + 0,
"B Y": 2 + 3,
"B Z": 3 + 6,
"C X": 2 + 0,
"C Y": 3 + 3,
"C Z": 1 + 6,
}
R = data.splitlines()
p1 = sum(S1[r] for r in R)
p2 = sum(S2[r] for r in R)
return p1, 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 == 12772
assert p2 == 11618

View file

@ -0,0 +1,28 @@
def solve(data):
rs = data.split()
p1 = sum(map(_p1, rs))
p2 = sum(map(_p2, zip(rs[::3], rs[1::3], rs[2::3])))
return p1, p2
def _p1(rs):
c = (set(rs[: len(rs) // 2]) & set(rs[len(rs) // 2 :])).pop()
return ord(c) - 96 if c.islower() else ord(c) - 38
def _p2(rsg):
c = (set(rsg[0]) & set(rsg[1]) & set(rsg[2])).pop()
return ord(c) - 96 if c.islower() else ord(c) - 38
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 == 7817
assert p2 == 2444

View file

@ -0,0 +1,31 @@
from output import ints
def solve(data):
p1 = sum(_p1(line) for line in data.split())
p2 = sum(_p2(line) for line in data.split())
return p1, p2
def _p1(data):
a1, a2, b1, b2 = ints(data)
return (a1 >= b1 and a2 <= b2) or (b1 >= a1 and b2 <= a2)
def _p2(data):
a1, a2, b1, b2 = ints(data)
return len(set(range(a1, a2 + 1)) & set(range(b1, b2 + 1))) > 0
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 == 507
assert p2 == 897

View file

@ -0,0 +1,45 @@
from copy import deepcopy
from collections import defaultdict
from output import ints
def solve(data):
state, program = data.split("\n\n")
labels, *state = state.splitlines()[::-1]
num = max(ints(labels))
stacks = defaultdict(list)
for r, text in enumerate(state):
for c in range(4 * num):
if c % 4 == 1:
if text[c] != " ":
stacks[c // 4 + 1].append(text[c])
p1 = _act(program, deepcopy(stacks))
p2 = _act(program, deepcopy(stacks), r=9001)
return p1, p2
def _act(program, stacks, r=9000):
for line in program.splitlines():
count, old, new = ints(line)
match r:
case 9000:
for _ in range(count):
stacks[new].append(stacks[old].pop())
case 9001:
stacks[new] += stacks[old][-count:]
stacks[old] = stacks[old][:-count]
return "".join(s[-1] for s in stacks.values())
if __name__ == "__main__":
with open("./input/05.txt", "r") as f:
inp = f.read()
p1, p2 = solve(inp)
print(p1)
print(p2)
assert p1 == "ZRLJGSCTR"
assert p2 == "PRTTGRFPB"

View file

@ -0,0 +1,21 @@
def solve(data):
for p1 in range(4, len(data)):
if len(set(data[p1 - 4 : p1])) == 4:
break
for p2 in range(14, len(data)):
if len(set(data[p2 - 14 : p2])) == 14:
break
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 == 1238
assert p2 == 3037

View file

@ -0,0 +1,54 @@
from collections import defaultdict
from output import ints
def solve(data):
fs = defaultdict(int)
pwd = []
for cmd in data.splitlines():
if cmd.startswith("$ ls") or cmd.startswith("dir "):
continue
if cmd.startswith("$ cd"):
d = cmd.split()[-1]
match d:
case "/":
pwd = []
case "..":
pwd.pop()
case _:
pwd.append(d)
continue
a = ""
w = sum(ints(cmd))
# in example input, all directories have distinct names.
#
# the puzzle input have repeated directory names, e.g. both
# /d/a and /c/b/a (a subfolder named "a") exists.
#
# Furthermore, puzzle input also has cases of /a/b/a,
# e.g. a recurring across directory path.
#
# Lost several hours due to this.
fs[a] += w
for p in pwd:
a += f"/{p}"
fs[a] += w
p1 = sum(i for i in fs.values() if i <= 100_000)
free = 70_000_000 - fs[""]
needed = 30_000_000 - free
p2 = min(i for i in fs.values() if i >= needed)
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 == 1644735
assert p2 == 1300850

View file

@ -0,0 +1,60 @@
from math import prod
from output import matrix
def solve(data):
M, R, C = matrix(data)
p1 = 2 * R + 2 * C - 4
p2 = 0
for row in range(1, R - 1):
for col in range(1, C - 1):
h = int(M[row][col])
visible = 0
score = []
for i, dy in enumerate(range(row - 1, -1, -1), start=1):
if h <= int(M[dy][col]):
break
else:
visible += 1
score.append(i)
for i, dx in enumerate(range(col + 1, C), start=1):
if h <= int(M[row][dx]):
break
else:
visible += 1
score.append(i)
for i, dy in enumerate(range(row + 1, R), start=1):
if h <= int(M[dy][col]):
break
else:
visible += 1
score.append(i)
for i, dx in enumerate(range(col - 1, -1, -1), start=1):
if h <= int(M[row][dx]):
break
else:
visible += 1
score.append(i)
if visible:
p1 += 1
p2 = max(prod(score), p2)
return p1, p2
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 == 1812
assert p2 == 315495

View file

@ -0,0 +1,71 @@
from output import DD, ints
def solve(data):
p12 = []
for sl in [2, 10]:
seen = set([(0, 0)])
snake = [(0, 0)] * sl
for line in data.splitlines():
d = line[0]
for i in range(ints(line)[0]):
ns = []
hd, *tls = snake
r, c = hd
hd = r + DD[d][0], c + DD[d][1]
ns.append(hd)
for tl in tls:
r, c = tl
match (r - hd[0], c - hd[1]):
case (2, -1):
tl = r - 1, c + 1
case (-2, -1):
tl = r + 1, c + 1
case (-2, 1):
tl = r + 1, c - 1
case (2, 1):
tl = r - 1, c - 1
case (1, 2):
tl = r - 1, c - 1
case (-1, 2):
tl = r + 1, c - 1
case (-1, -2):
tl = r + 1, c + 1
case (1, -2):
tl = r - 1, c + 1
case (0, 2):
tl = r, c - 1
case (0, -2):
tl = r, c + 1
case (2, 0):
tl = r - 1, c
case (-2, 0):
tl = r + 1, c
case (2, -2):
tl = r - 1, c + 1
case (-2, -2):
tl = r + 1, c + 1
case (-2, 2):
tl = r + 1, c - 1
case (2, 2):
tl = r - 1, c - 1
ns.append(tl)
hd = tl
snake = ns
seen.add(tl)
p12.append(len(seen))
p1, p2 = p12
return p1, p2
if __name__ == "__main__":
with open("./input/09.txt", "r") as f:
inp = f.read().strip()
p1, p2 = solve(inp)
print(p1)
print(p2)
assert p1 == 6212
assert p2 == 2522

View file

@ -0,0 +1,49 @@
from output import sints
def solve(data):
x = 1
P = data.splitlines()
p1 = 0
c = 0
p = 0
running = True
busy = False
pixels = []
while running:
if not p < len(P) and not busy:
running = False
continue
line = P[min([p, len(P) - 1])]
if (c + 21) % 40 == 0:
p1 += (c + 1) * x
if c % 40 == 0:
pixels.append("\n")
pixels.append("" if (x - 1) <= (c % 40) <= (x + 1) else " ")
if busy:
busy = False
x += int(sints(line)[0])
p += 1
c += 1
continue
if line.startswith("noop"):
p += 1
c += 1
continue
busy = True
c += 1
p2 = "".join(pixels)
return p1, p2
if __name__ == "__main__":
with open("./input/10.txt", "r") as f:
inp = f.read().strip()
p1, p2 = solve(inp)
print(p1)
print(p2)
assert p1 == 11820
# assert p2 == "EPJBRKAH"

View file

@ -0,0 +1,74 @@
from copy import deepcopy
from collections import defaultdict
from output import ints
def solve(data):
M = []
for md in data.split("\n\n"):
m = {}
starting_items, operation, divisor, if_true, if_false = md.splitlines()[1:]
m["items"] = ints(starting_items)
m["if_false"] = ints(if_false)[0]
m["if_true"] = ints(if_true)[0]
m["divisor"] = ints(divisor)[0]
m["operation_values"] = operation.split()[-3:]
M.append(m)
p12 = []
# Part 2 resolver.
#
# Not sure what to call this, so I go for Greatest Common
# Divisor. Had to look for hints at subreddit to find it out.
# It basically fasten up the computation speed by keeping
# the numbers low.
#
# Apparently, this is common Modular arithmetic:
# https://en.wikipedia.org/wiki/Modular_arithmetic
gcd = 1
for d in [m["divisor"] for m in M]:
gcd *= d
for rounds, wld in [(20, True), (10_000, False)]:
B = defaultdict(int)
MM = deepcopy(M)
for _ in range(rounds):
for i, m in enumerate(MM):
while m["items"]:
wl = m["items"].pop(0)
B[i] += 1
x, y, z = m["operation_values"]
x = int(wl) if x == "old" else int(x)
z = int(wl) if z == "old" else int(z)
match y:
case "+":
wl = x + z
case "*":
wl = x * z
if wld:
wl = wl // 3
else:
wl = wl % gcd
if wl % m["divisor"] == 0:
MM[m["if_true"]]["items"].append(wl)
else:
MM[m["if_false"]]["items"].append(wl)
a, b, *_ = sorted(B.values(), reverse=True)
p12.append(a * b)
p1, p2 = p12
return p1, p2
def _state(M):
return tuple([(tuple(m["items"])) for m in M])
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 == 50616
assert p2 == 11309046332

View file

@ -0,0 +1,58 @@
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, DDa, vvdbg, DD, ADJ, ints, mhd, mdbg, vdbg, cw, ccw, bk
def solve(data):
M, H, W = matrix(data)
E = S = None
p1 = p2 = H * W
SP = []
for rr in range(H):
for cc in range(W):
if M[rr][cc] == "E":
E = (rr, cc)
if M[rr][cc] == "S":
S = (rr, cc)
SP.append((rr, cc))
if M[rr][cc] == "a":
SP.append((rr, cc))
M = [list(row) for row in M]
for rc, v in [(S, "a"), (E, "z")]:
r, c = rc
M[r][c] = v
for sp in SP:
Q = [(sp, ord("a"), 0)]
seen = set()
while Q:
yx, e, s = Q.pop(0)
if yx in seen:
continue
seen.add(yx)
if yx == E:
if sp == S:
p1 = s
p2 = min(p2, s)
y, x = yx
for dy, dx in D:
if 0 <= y + dy < H and 0 <= x + dx < W:
n = ord(M[y + dy][x + dx])
if n - e <= 1:
Q.append(((y + dy, x + dx), n, s + 1))
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 == 517
assert p2 == 512