Skip to content

Instantly share code, notes, and snippets.

@tnlogy
Last active December 12, 2022 18:49
Show Gist options
  • Save tnlogy/97a84616820febc1d09cb084d28ec92d to your computer and use it in GitHub Desktop.
Save tnlogy/97a84616820febc1d09cb084d28ec92d to your computer and use it in GitHub Desktop.
advent of code 2022 - don't look unless you have completed it :)
import numpy as np
def one(part=2):
"""Find the maximum sum, or the three maximum sums for rows of values"""
with open('input.txt', 'r') as f:
data = [np.sum(np.fromstring(d, sep="\n", dtype=int)) for d in f.read().split("\n\n")]
if part == 2:
print("one:2:", np.sum(np.sort(data)[-3:]))
else:
print("one:", np.sum(np.sort(data)[-1]))
def two(part=2):
"""Calculate the score for Rock, Paper, Scissors game, according to wanted move or wanted outcome"""
score = dict(
A=dict(X=3, Y=6, Z=0),
B=dict(X=0, Y=3, Z=6),
C=dict(X=6, Y=0, Z=3)
)
shape_score = dict(X=1, Y=2, Z=3)
wanted_outcome = dict(X=0, Y=3, Z=6)
s = 0
for a, b in np.genfromtxt("input2.txt", dtype=(str, str)):
if part == 2:
o = wanted_outcome[b]
move = next(move for move, outcome in score[a].items() if outcome == o) # reverse lookup
s += score[a][move] + shape_score[move]
else:
s += score[a][b] + shape_score[b]
print(f"two:{part}:", s)
def three():
"""Find the common items in the rucksacks, and sum the priority values"""
keys = {k: v+1 for v, k in enumerate("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")}
with open('input3.txt', 'r') as f:
s = 0
for r in f:
h = int(len(r)/2)
a, b = r[:h], r[h:]
d = set.intersection(set(a), set(b)).pop()
s += keys[d]
print("three:", s)
def three2():
"""Find the common items in the rucksacks for three rows, and sum the priority values"""
keys = {k: v+1 for v, k in enumerate("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")}
with open('input3.txt', 'r') as f:
s = 0
rows = f.read().splitlines()
for a, b, c in zip(rows[::3], rows[1::3], rows[2::3]):
d = set.intersection(set(a), set(b), set(c)).pop()
s += keys[d]
print("three:2:", s)
def four(part=2):
"""Find number of pairs that are subsets, or not disjoint"""
with open('input4.txt', 'r') as f:
s = 0
for r in f:
a, b = r.split(",")
a_min, a_max = a.split("-")
b_min, b_max = b.split("-")
ar, br = range(int(a_min), int(a_max) +1), range(int(b_min), int(b_max) + 1)
a_s, b_s = set(ar), set(br)
if part == 2:
if not a_s.isdisjoint(b_s):
s += 1
else:
if a_s.issubset(b_s) or b_s.issubset(a_s):
s += 1
print(f"four:{part}", s)
def five(part=2):
"""Print top rows of crates after N move operations"""
with open('input5.txt', 'r') as f:
stacks, code = f.read().split("\n\n")
# parse stacks
stacks = stacks.splitlines()[:-1]
d = np.array([[k for k in row] for row in stacks])
stacks = [np.flip(r[r != ' ']).tolist() for r in d[:, 1::4].T]
for r in code.split("\n"):
x = r[5:].split(" from ")
fr, to = x[1].split(" to ")
fr, to = int(fr), int(to)
count = int(x[0])
if part == 2:
stacks[to-1] += stacks[fr-1][-count:]
stacks[fr-1] = stacks[fr-1][:-count]
else:
for c in range(0, count):
stacks[to-1].append(stacks[fr-1].pop())
print(f"five:{part}: ", end="")
for s in stacks:
print(s[-1], end="")
print()
def six(part=1):
"""Print position in file after first number of distinct markers"""
with open('input6.txt', 'r') as f:
data = f.read()
n_distinct_markers = 4 if part == 1 else 14
# loop over a window (win) of length n_distinct_markers to check when all chars are distinct
for p in range(0, len(data)):
win = data[p:p+n_distinct_markers]
if len(set(win)) == n_distinct_markers:
print(f"six:{part}:", p+n_distinct_markers)
return
def seven():
"""Parse directory listing and sum size of folders"""
class Dir:
def __init__(self, name):
self.name, self.files, self._size = name, [], None
def add(self, file):
self.files.append(file)
def get_dir(self, name):
return next(file for file in self.files if file.name == name)
@property
def size(self):
if not self._size:
self._size = sum(file.size for file in self.files)
return self._size
def get_dirs(self, cond, dirs=None):
dirs = [] if dirs is None else dirs
if cond(self):
dirs.append(self)
for file in self.files:
file.get_dirs(cond, dirs)
return dirs
class File:
def __init__(self, name, size):
self.name, self.size = name, size
def get_size(self):
return self.size
def get_dirs(self, cond, res):
pass
with open('input7.txt', 'r') as f:
root = Dir("/")
cwd = [root]
for line in f.read().splitlines()[1:]:
if line.startswith("$"):
cmd = line[2:].split(" ")
if cmd[0] == "cd":
if cmd[1] == "..":
cwd.pop()
else:
cwd.append(cwd[-1].get_dir(cmd[1]))
else: # ls result
if line.startswith("dir "):
_, name = line.split(" ")
cwd[-1].add(Dir(name))
else:
size, name = line.split(" ")
cwd[-1].add(File(name, int(size)))
print("seven:1:", sum(file.size for file in root.get_dirs(lambda x: x.size <= 100000)))
needed = 30000000 - (70000000 - root.size)
print("seven:2:", min(file.size for file in root.get_dirs(lambda x: x.size > needed)))
def eight(part=2):
def los(d, v):
"""line of sight: how far can you see in the array?"""
return next((i+1 for i, x in enumerate(d) if x >= v), len(list(d)))
with open('input8.txt', 'r') as f:
d = np.array([[int(k) for k in row] for row in f.read().splitlines()]) # make a 2D array
s = 0
for i, j in np.ndindex(d.shape):
if i == 0 or j == 0 or (d.shape[1] - 1) == i or (d.shape[0] - 1) == j:
if part == 1:
s += 1
else:
v = d[j][i]
if part == 1:
if max(d[0:j, i]) < v or max(d[j+1:, i]) < v or max(d[j, 0:i]) < v or max(d[j, i+1:]) < v:
s += 1
if part == 2: # multiply line of sight in 4 directions
s = max(los(np.flip(d[0:j, i]), v) * los(d[j+1:, i], v) *
los(np.flip(d[j, 0:i]), v) * los(d[j, i+1:], v), s)
print(f"eight:{part}:", s)
def nine(part=2):
"""How many positions does the tail of the rope visit at least once?"""
Pos = namedtuple("Pos", ["x", "y"])
def update_tail(head, tail):
new_pos = Pos(tail.x + np.sign(head.x - tail.x), tail.y + np.sign(head.y - tail.y))
if head == tail or head == new_pos or (abs(head.x - tail.x) == 1 and abs(head.y - tail.y) == 1):
return tail
else:
return new_pos
path = []
H, TL = Pos(0, 0), [Pos(0, 0) for _ in range(0, 1 if part == 1 else 9)]
dir_map = dict(R=Pos(1, 0), L=Pos(-1, 0), U=Pos(0, 1), D=Pos(0, -1))
for d, l in np.genfromtxt("input9.txt", dtype="U1,int"):
direction = dir_map[d]
for i in range(0, l):
H = Pos(H.x + direction.x, H.y + direction.y)
PH = H
for j in range(0, len(TL)):
PH = update_tail(PH, TL[j])
TL[j] = PH
path.append(TL[-1])
print(f"nine:{part}:", len(set(path)))
def ten(part=1):
with open('input10.txt', 'r') as f:
cycles = [1]
X = 1
for row in f.read().splitlines():
if row == "noop":
cycles.append(X)
else:
_, v = row.split(" ")
cycles.append(X)
cycles.append(X)
X += int(v)
cs = [20, 60, 100, 140, 180, 220]
print([cycles[c] for c in cs])
res = [c * cycles[c] for c in cs]
print(res)
print(sum(res))
screen = ""
for y in range(0, 6):
for x in range(0, 40):
if abs(cycles[x + y*40 +1] - x) < 2:
screen += "#"
else:
screen += "."
screen += "\n"
print(screen)
pass
def eleven(part=1):
"""To slow for part 2 so far..."""
class Monkey:
def __init__(self, *args):
self.items, self.expr, self.div_by, self.true, self.false = args
self.inspect_count = 0
with open('input11.txt', 'r') as f:
data = f.read().split("\n\n")
monkeys = []
for m in data:
rows = m.split("\n")
# eval(expr, dict(old=3))
monkeys.append(Monkey([int(v) for v in rows[1][18:].split(",")], rows[2].split("=")[1],
int(rows[3][21:]), int(rows[4][29:]), int(rows[5][30:])))
for rounds in range(20 if part == 1 else 10000):
for m in monkeys:
for i in m.items:
v = eval(m.expr, dict(old=i))
if part == 1:
v = math.floor(v/3)
m.inspect_count += 1
if v % m.div_by == 0:
monkeys[m.true].items.append(v)
else:
monkeys[m.false].items.append(v)
m.items = []
if (rounds % 100) == 0:
print("round", rounds)
two_highest = np.sort([m.inspect_count for m in monkeys])[-2:]
print(two_highest)
print(np.multiply(*two_highest))
def twelve(part=1):
import astar as astar
Node = namedtuple("Node", "x y")
with open('input12.txt', 'r') as f:
maze = np.array([[k for k in row] for row in f.read().splitlines()]) # make a 2D array
S, E = Node(*np.argwhere(maze == 'S')[0]), Node(*np.argwhere(maze == 'E')[0])
maze[S.x, S.y], maze[E.x, E.y] = 'a', 'z'
def neighbors(n):
def valid_path(x, y):
return 0 <= x < maze.shape[0] and 0 <= y < maze.shape[1] and ord(maze[x, y]) - 1 <= ord(v)
v = maze[n.x, n.y]
for delta in [Node(-1, 0), Node(1, 0), Node(0, -1), Node(0, 1)]:
if valid_path(n.x + delta.x, n.y + delta.y):
yield Node(n.x + delta.x, n.y + delta.y)
def manhattan_distance(a, b):
return abs(a.x - b.x) + abs(a.y - b.y)
if part == 1:
path = list(astar.find_path(S, E, neighbors_fnct=neighbors,
heuristic_cost_estimate_fnct=manhattan_distance))
print("twelve:1:", len(path) - 1)
else: # Quite slow, but works. Should be able to store previous results from 'a'-nodes to speed up.
res = 100000
for S in np.argwhere(maze == 'a'):
path = astar.find_path(Node(*S), E, neighbors_fnct=neighbors,
heuristic_cost_estimate_fnct=manhattan_distance)
if path:
l = len(list(path)) - 1
if l < res:
res = l
print("twelve:2:", res)
if __name__ == '__main__':
one(1)
one(2)
two(1)
two(2)
three()
three2()
four(1)
four(2)
five(1)
five(2)
six(1)
six(2)
seven()
eight(1)
eight(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment