Compare commits
13 commits
a8cf7bf5e7
...
92df810943
| Author | SHA1 | Date | |
|---|---|---|---|
| 92df810943 | |||
| 81c6bc4cd8 | |||
| 0f709f9f03 | |||
| 657fe956f9 | |||
| 179203f7be | |||
| 90d5ab203d | |||
| a708d791c2 | |||
| e800a005e8 | |||
| 7c25aeafd7 | |||
| 19790f0899 | |||
| 597940f1b4 | |||
| e791b19ab2 | |||
| 7b5c9c393b |
15 changed files with 924 additions and 0 deletions
48
2022-python/README.md
Normal file
48
2022-python/README.md
Normal 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
118
2022-python/aoc.py
Normal 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("")
|
||||
201
2022-python/output/__init__.py
Normal file
201
2022-python/output/__init__.py
Normal 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
|
||||
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)
|
||||
26
2022-python/output/day_01.py
Normal file
26
2022-python/output/day_01.py
Normal 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
|
||||
40
2022-python/output/day_02.py
Normal file
40
2022-python/output/day_02.py
Normal 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
|
||||
28
2022-python/output/day_03.py
Normal file
28
2022-python/output/day_03.py
Normal 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
|
||||
31
2022-python/output/day_04.py
Normal file
31
2022-python/output/day_04.py
Normal 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
|
||||
45
2022-python/output/day_05.py
Normal file
45
2022-python/output/day_05.py
Normal 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"
|
||||
21
2022-python/output/day_06.py
Normal file
21
2022-python/output/day_06.py
Normal 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
|
||||
54
2022-python/output/day_07.py
Normal file
54
2022-python/output/day_07.py
Normal 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
|
||||
60
2022-python/output/day_08.py
Normal file
60
2022-python/output/day_08.py
Normal 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
|
||||
71
2022-python/output/day_09.py
Normal file
71
2022-python/output/day_09.py
Normal 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
|
||||
49
2022-python/output/day_10.py
Normal file
49
2022-python/output/day_10.py
Normal 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"
|
||||
74
2022-python/output/day_11.py
Normal file
74
2022-python/output/day_11.py
Normal 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
|
||||
58
2022-python/output/day_12.py
Normal file
58
2022-python/output/day_12.py
Normal 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
|
||||
Loading…
Add table
Reference in a new issue