[Python/2018] Move solutions into .py files

This commit is contained in:
Felix Bargfeldt 2023-10-29 17:04:13 +01:00
parent edb04277c6
commit 40e767096e
Signed by: Defelo
GPG key ID: 2A05272471204DD3
60 changed files with 1518 additions and 3541 deletions

23
Python/2018/01.py Normal file
View file

@ -0,0 +1,23 @@
from lib import *
input = read_input(2018, 1)
out = 0
for line in input.splitlines():
out += int(line)
print(out)
lines = input.splitlines()
freq = 0
seen = {0}
while True:
for line in lines:
freq += int(line)
if freq in seen:
print(freq)
break
else:
seen.add(freq)
else:
continue
break

View file

@ -1,4 +0,0 @@
out = 0
for line in open("input.txt").read().splitlines():
out += int(line)
print(out)

View file

@ -1,11 +0,0 @@
lines = open("input.txt").read().splitlines()
freq = 0
seen = {0}
while True:
for line in lines:
freq += int(line)
if freq in seen:
print(freq)
exit()
else:
seen.add(freq)

30
Python/2018/02.py Normal file
View file

@ -0,0 +1,30 @@
from lib import *
input = read_input(2018, 2)
def count(box, n):
return any(box.count(c) == n for c in set(box))
counter = {2: 0, 3: 0}
for line in input.splitlines():
counter[2] += count(line, 2)
counter[3] += count(line, 3)
print(counter[2] * counter[3])
def compare(a, b):
return len(a) == len(b) and sum(x != y for x, y in zip(a, b)) == 1
lines = input.splitlines()
for a in lines:
for b in lines:
if compare(a, b):
print("".join(x for x, y in zip(a, b) if x == y))
break
else:
continue
break

View file

@ -1,9 +0,0 @@
def count(box, n):
return any(box.count(c) == n for c in set(box))
counter = {2: 0, 3: 0}
for line in open("input.txt").read().splitlines():
counter[2] += count(line, 2)
counter[3] += count(line, 3)
print(counter[2] * counter[3])

View file

@ -1,9 +0,0 @@
def compare(a, b):
return len(a) == len(b) and sum(x != y for x, y in zip(a, b)) == 1
lines = open("input.txt").read().splitlines()
for a in lines:
for b in lines:
if compare(a, b):
print("".join(x for x, y in zip(a, b) if x == y))
exit()

View file

@ -1,6 +1,19 @@
from lib import *
input = read_input(2018, 3)
import re
claims = open("input.txt").read().splitlines()
G = [[0 for _ in range(1000)] for _ in range(1000)]
for line in input.splitlines():
offx, offy, wid, hei = map(int, re.match("^#\d+ @ (\d+),(\d+): (\d+)x(\d+)$", line).groups())
for x in range(wid):
for y in range(hei):
G[offx + x][offy + y] += 1
print(sum(x >= 2 for row in G for x in row))
claims = input.splitlines()
G = [[0 for _ in range(1000)] for _ in range(1000)]
for line in claims:
@ -12,3 +25,4 @@ for line in claims:
id, offx, offy, wid, hei = map(int, re.match("^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$", line).groups())
if all(G[offx + x][offy + y] == 1 for x in range(wid) for y in range(hei)):
print(id)
break

View file

@ -1,9 +0,0 @@
import re
G = [[0 for _ in range(1000)] for _ in range(1000)]
for line in open("input.txt").read().splitlines():
offx, offy, wid, hei = map(int, re.match("^#\d+ @ (\d+),(\d+): (\d+)x(\d+)$", line).groups())
for x in range(wid):
for y in range(hei):
G[offx + x][offy + y] += 1
print(sum(x>=2 for row in G for x in row))

81
Python/2018/04.py Normal file
View file

@ -0,0 +1,81 @@
from lib import *
input = read_input(2018, 4)
days = {}
for line in input.splitlines():
day, hour, minute, action = re.match("^\[(\d\d\d\d-\d\d-\d\d) (\d\d):(\d\d)\] (.*)$", line).groups()
day = date.fromisoformat(day)
hour, minute = int(hour), int(minute)
match = re.match(r"^Guard #(\d+) begins shift$", action)
if match:
guard = int(match.group(1))
if hour == 23:
day += timedelta(days=1)
days.setdefault(day, [None, [None for _ in range(60)]])[0] = guard
elif action == "wakes up":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = True
elif action == "falls asleep":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = False
else:
assert False
guards = {}
for day, (guard, logs) in days.items():
awake = True
for i in range(60):
if logs[i] is None:
logs[i] = awake
else:
awake = logs[i]
if not awake:
guards.setdefault(guard, [0, {}])[0] += 1
guards[guard][1][i] = guards[guard][1].get(i, 0) + 1
guard = max(guards, key=lambda g: guards[g][0])
print(guard * max(guards[guard][1], key=lambda d: guards[guard][1][d]))
days = {}
for line in input.splitlines():
day, hour, minute, action = re.match("^\[(\d\d\d\d-\d\d-\d\d) (\d\d):(\d\d)\] (.*)$", line).groups()
day = date.fromisoformat(day)
hour, minute = int(hour), int(minute)
match = re.match("^Guard #(\d+) begins shift$", action)
if match:
guard = int(match.group(1))
if hour == 23:
day += timedelta(days=1)
days.setdefault(day, [None, [None for _ in range(60)]])[0] = guard
elif action == "wakes up":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = True
elif action == "falls asleep":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = False
else:
assert False
guards = {}
for day, (guard, logs) in days.items():
awake = True
for i in range(60):
if logs[i] is None:
logs[i] = awake
else:
awake = logs[i]
if not awake:
guards.setdefault(guard, [0, {}])[0] += 1
guards[guard][1][i] = guards[guard][1].get(i, 0) + 1
best_cnt = -1
out = None
for g in guards:
cnt, best_minute = max((guards[g][1].get(i, 0), i) for i in range(60))
if cnt > best_cnt:
best_cnt = cnt
out = best_minute * g
print(out)

View file

@ -1,37 +0,0 @@
from datetime import date, timedelta
import re
days = {}
for line in open("input.txt").read().splitlines():
day, hour, minute, action = re.match("^\[(\d\d\d\d-\d\d-\d\d) (\d\d):(\d\d)\] (.*)$", line).groups()
day = date.fromisoformat(day)
hour, minute = int(hour), int(minute)
match = re.match("^Guard #(\d+) begins shift$", action)
if match:
guard = int(match.group(1))
if hour == 23:
day += timedelta(days=1)
days.setdefault(day, [None, [None for _ in range(60)]])[0] = guard
elif action == "wakes up":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = True
elif action == "falls asleep":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = False
else:
assert False
guards = {}
for day, (guard, logs) in days.items():
awake = True
for i in range(60):
if logs[i] is None:
logs[i] = awake
else:
awake = logs[i]
if not awake:
guards.setdefault(guard, [0, {}])[0] += 1
guards[guard][1][i] = guards[guard][1].get(i, 0) + 1
guard = max(guards, key=lambda g: guards[g][0])
print(guard * max(guards[guard][1], key=lambda d: guards[guard][1][d]))

View file

@ -1,43 +0,0 @@
from datetime import date, timedelta
import re
days = {}
for line in open("input.txt").read().splitlines():
day, hour, minute, action = re.match("^\[(\d\d\d\d-\d\d-\d\d) (\d\d):(\d\d)\] (.*)$", line).groups()
day = date.fromisoformat(day)
hour, minute = int(hour), int(minute)
match = re.match("^Guard #(\d+) begins shift$", action)
if match:
guard = int(match.group(1))
if hour == 23:
day += timedelta(days=1)
days.setdefault(day, [None, [None for _ in range(60)]])[0] = guard
elif action == "wakes up":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = True
elif action == "falls asleep":
assert hour == 0
assert 0 <= minute < 60
days.setdefault(day, [None, [None for _ in range(60)]])[1][minute] = False
else:
assert False
guards = {}
for day, (guard, logs) in days.items():
awake = True
for i in range(60):
if logs[i] is None:
logs[i] = awake
else:
awake = logs[i]
if not awake:
guards.setdefault(guard, [0, {}])[0] += 1
guards[guard][1][i] = guards[guard][1].get(i, 0) + 1
best_cnt = -1
out = None
for g in guards:
cnt, best_minute = max((guards[g][1].get(i, 0), i) for i in range(60))
if cnt > best_cnt:
best_cnt = cnt
out = best_minute * g
print(out)

View file

@ -1,3 +1,16 @@
from lib import *
input = read_input(2018, 5)
stack = []
for c in input.strip():
if stack and stack[-1].lower() == c.lower() and stack[-1].islower() != c.islower():
stack.pop()
else:
stack.append(c)
print(len(stack))
def react(poly, wo):
stack = []
for c in poly:
@ -9,5 +22,6 @@ def react(poly, wo):
stack.append(c)
return len(stack)
inp = open("input.txt").read().strip()
inp = input.strip()
print(min(react(inp, c) for c in set(inp.lower())))

View file

@ -1,7 +0,0 @@
stack = []
for c in open("input.txt").read().strip():
if stack and stack[-1].lower() == c.lower() and stack[-1].islower() != c.islower():
stack.pop()
else:
stack.append(c)
print(len(stack))

View file

@ -1,19 +1,25 @@
from lib import *
input = read_input(2018, 6)
width = 0
height = 0
coords = []
for line in open("input.txt").read().splitlines():
for line in input.splitlines():
x, y = map(int, line.split(", "))
coords.append((x, y))
width = max(width, x + 1)
height = max(height, y + 1)
def find_nearest(x, y):
distances = [abs(x-p) + abs(y-q) for p, q in coords]
distances = [abs(x - p) + abs(y - q) for p, q in coords]
best_distance = min(distances)
if distances.count(best_distance) > 1:
return None
return distances.index(best_distance)
counter = {}
edge = set()
for y in range(height):
@ -24,3 +30,18 @@ for y in range(height):
if x in (0, width - 1) or y in (0, height - 1):
edge.add(nearest)
print(max(counter[c] for c in counter if c not in edge))
width = 0
height = 0
coords = []
for line in input.splitlines():
x, y = map(int, line.split(", "))
coords.append((x, y))
width = max(width, x + 1)
height = max(height, y + 1)
def measure(x, y):
return sum(abs(x - p) + abs(y - q) for p, q in coords)
print(sum(measure(x, y) < 10000 for x in range(width) for y in range(height)))

View file

@ -1,13 +0,0 @@
width = 0
height = 0
coords = []
for line in open("input.txt").read().splitlines():
x, y = map(int, line.split(", "))
coords.append((x, y))
width = max(width, x + 1)
height = max(height, y + 1)
def measure(x, y):
return sum(abs(x-p) + abs(y-q) for p, q in coords)
print(sum(measure(x, y) < 10000 for x in range(width) for y in range(height)))

View file

@ -1,9 +1,35 @@
import re
from lib import *
input = read_input(2018, 7)
unlocks = {}
requirements = {}
chars = set()
for line in open("input.txt").read().splitlines():
for line in input.splitlines():
a, b = re.match("^Step (.) must be finished before step (.) can begin\.$", line).groups()
chars |= {a, b}
unlocks.setdefault(a, set()).add(b)
requirements.setdefault(b, set()).add(a)
out = ""
Q = [e for e in chars if e not in requirements]
heapq.heapify(Q)
while Q:
p = heapq.heappop(Q)
out += p
for q in unlocks.get(p, []):
requirements[q].remove(p)
if not requirements[q]:
heapq.heappush(Q, q)
print(out)
unlocks = {}
requirements = {}
chars = set()
for line in input.splitlines():
a, b = re.match("^Step (.) must be finished before step (.) can begin\.$", line).groups()
chars |= {a, b}
unlocks.setdefault(a, set()).add(b)
@ -11,19 +37,21 @@ for line in open("input.txt").read().splitlines():
Q = [e for e in chars if e not in requirements]
seconds = 0
def get_task():
if Q:
task = Q.pop()
return (task, ord(task) - 4)
def finish_task(p):
for q in unlocks.get(p, []):
requirements[q].remove(p)
if not requirements[q]:
Q.append(q)
def fast_forward():
t = min((w[1] for w in workers if w is not None), default=0)
for i in range(5):
@ -35,6 +63,7 @@ def fast_forward():
workers[i] = None
return t
workers = [None for _ in range(5)]
while Q or any(workers):
seconds += fast_forward()

View file

@ -1,24 +0,0 @@
import heapq
import re
unlocks = {}
requirements = {}
chars = set()
for line in open("input.txt").read().splitlines():
a, b = re.match("^Step (.) must be finished before step (.) can begin\.$", line).groups()
chars |= {a, b}
unlocks.setdefault(a, set()).add(b)
requirements.setdefault(b, set()).add(a)
out = ""
Q = [e for e in chars if e not in requirements]
heapq.heapify(Q)
while Q:
p = heapq.heappop(Q)
out += p
for q in unlocks.get(p, []):
requirements[q].remove(p)
if not requirements[q]:
heapq.heappush(Q, q)
print(out)

41
Python/2018/08.py Normal file
View file

@ -0,0 +1,41 @@
from lib import *
input = read_input(2018, 8)
(*nums,) = map(int, input.split())
def get_metadata_sum():
child_count = nums.pop(0)
meta_count = nums.pop(0)
out = 0
for _ in range(child_count):
out += get_metadata_sum()
for _ in range(meta_count):
out += nums.pop(0)
return out
print(get_metadata_sum())
(*nums,) = map(int, input.split())
def get_value():
child_count = nums.pop(0)
meta_count = nums.pop(0)
out = 0
childs = [get_value() for _ in range(child_count)]
for _ in range(meta_count):
num = nums.pop(0)
if not child_count:
out += num
elif 1 <= num <= child_count:
out += childs[num - 1]
return out
print(get_value())

View file

@ -1,13 +0,0 @@
*nums, = map(int, open("input.txt").read().split())
def get_metadata_sum():
child_count = nums.pop(0)
meta_count = nums.pop(0)
out = 0
for _ in range(child_count):
out += get_metadata_sum()
for _ in range(meta_count):
out += nums.pop(0)
return out
print(get_metadata_sum())

View file

@ -1,18 +0,0 @@
*nums, = map(int, open("input.txt").read().split())
def get_value():
child_count = nums.pop(0)
meta_count = nums.pop(0)
out = 0
childs = [get_value() for _ in range(child_count)]
for _ in range(meta_count):
num = nums.pop(0)
if not child_count:
out += num
elif 1 <= num <= child_count:
out += childs[num - 1]
return out
print(get_value())

34
Python/2018/09.py Normal file
View file

@ -0,0 +1,34 @@
from lib import *
input = read_input(2018, 9)
players, n = map(int, re.match(r"^(\d+) players; last marble is worth (\d+) points$", input).groups())
lst = deque([0])
scores = [0 for _ in range(players)]
for i in range(1, n + 1):
p = i % players
if i % 23:
lst.rotate(-1)
lst.append(i)
else:
lst.rotate(7)
scores[p] += i + lst.pop()
lst.rotate(-1)
print(max(scores))
players, n = map(int, re.match(r"^(\d+) players; last marble is worth (\d+) points$", input).groups())
n *= 100
lst = deque([0])
scores = [0 for _ in range(players)]
for i in range(1, n + 1):
p = i % players
if i % 23:
lst.rotate(-1)
lst.append(i)
else:
lst.rotate(7)
scores[p] += i + lst.pop()
lst.rotate(-1)
print(max(scores))

View file

@ -1,16 +0,0 @@
from collections import deque
import re
players, n = map(int, re.match(r"^(\d+) players; last marble is worth (\d+) points$", open("input.txt").read()).groups())
lst = deque([0])
scores = [0 for _ in range(players)]
for i in range(1, n + 1):
p = i % players
if i % 23:
lst.rotate(-1)
lst.append(i)
else:
lst.rotate(7)
scores[p] += i + lst.pop()
lst.rotate(-1)
print(max(scores))

View file

@ -1,17 +0,0 @@
from collections import deque
import re
players, n = map(int, re.match(r"^(\d+) players; last marble is worth (\d+) points$", open("input.txt").read()).groups())
n *= 100
lst = deque([0])
scores = [0 for _ in range(players)]
for i in range(1, n + 1):
p = i % players
if i % 23:
lst.rotate(-1)
lst.append(i)
else:
lst.rotate(7)
scores[p] += i + lst.pop()
lst.rotate(-1)
print(max(scores))

66
Python/2018/10.py Normal file
View file

@ -0,0 +1,66 @@
from lib import *
input = read_input(2018, 10)
points = []
for line in input.splitlines():
x, y, vx, vy = map(int, re.match(r"^position=< *(-?\d+), *(-?\d+)> velocity=< *(-?\d+), *(-?\d+)>$", line).groups())
points.append((x, y, vx, vy))
i = 0
best = 1e1337
prev = None
while True:
p = {}
minx = miny = 1e1337
maxx = maxy = -1e1337
for x, y, vx, vy in points:
x += vx * i
y += vy * i
minx = min(x, minx)
maxx = max(x, maxx)
miny = min(y, miny)
maxy = max(y, maxy)
p[(x, y)] = True
dist = maxx - minx + maxy - miny
if dist < best:
best = dist
i += 1
prev = p
else:
for y in range(miny, maxy + 1):
print("".join(" #"[prev.get((x, y), False)] for x in range(minx, maxx + 1)))
break
points = []
for line in input.splitlines():
x, y, vx, vy = map(int, re.match(r"^position=< *(-?\d+), *(-?\d+)> velocity=< *(-?\d+), *(-?\d+)>$", line).groups())
points.append((x, y, vx, vy))
i = 0
best = 1e1337
prev = None
while True:
p = {}
minx = miny = 1e1337
maxx = maxy = -1e1337
for x, y, vx, vy in points:
x += vx * i
y += vy * i
minx = min(x, minx)
maxx = max(x, maxx)
miny = min(y, miny)
maxy = max(y, maxy)
p[(x, y)] = True
dist = maxx - minx + maxy - miny
if dist < best:
best = dist
i += 1
prev = p
else:
print(i - 1)
break

View file

@ -1,32 +0,0 @@
import re
points = []
for line in open("input.txt").read().splitlines():
x, y, vx, vy = map(int, re.match(r"^position=< *(-?\d+), *(-?\d+)> velocity=< *(-?\d+), *(-?\d+)>$", line).groups())
points.append((x, y, vx, vy))
i = 0
best = 1e1337
prev = None
while True:
p = {}
minx = miny = 1e1337
maxx = maxy = -1e1337
for x, y, vx, vy in points:
x += vx * i
y += vy * i
minx = min(x, minx)
maxx = max(x, maxx)
miny = min(y, miny)
maxy = max(y, maxy)
p[(x, y)] = True
dist = maxx - minx + maxy - miny
if dist < best:
best = dist
i += 1
prev = p
else:
for y in range(miny, maxy + 1):
print("".join(" #"[prev.get((x, y), False)] for x in range(minx, maxx + 1)))
break

View file

@ -1,31 +0,0 @@
import re
points = []
for line in open("input.txt").read().splitlines():
x, y, vx, vy = map(int, re.match(r"^position=< *(-?\d+), *(-?\d+)> velocity=< *(-?\d+), *(-?\d+)>$", line).groups())
points.append((x, y, vx, vy))
i = 0
best = 1e1337
prev = None
while True:
p = {}
minx = miny = 1e1337
maxx = maxy = -1e1337
for x, y, vx, vy in points:
x += vx * i
y += vy * i
minx = min(x, minx)
maxx = max(x, maxx)
miny = min(y, miny)
maxy = max(y, maxy)
p[(x, y)] = True
dist = maxx - minx + maxy - miny
if dist < best:
best = dist
i += 1
prev = p
else:
print(i - 1)
break

View file

@ -1,173 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 11"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 11\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'243,72'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" serial = int(puzzle)\n",
" get = lambda x, y: ((((x+10)*y+serial)*(x+10))//100)%10 - 5\n",
" \n",
" return \",\".join(map(str, max(\n",
" ((x, y)\n",
" for x in range(1, 299)\n",
" for y in range(1, 299)),\n",
" key=lambda k: sum(get(k[0]+i, k[1]+j) for i in range(3) for j in range(3))\n",
" )))\n",
" \n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"560 ms ± 72.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'229,192,11'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" serial = int(puzzle)\n",
" get = lambda x, y: ((((x+10)*y+serial)*(x+10))//100)%10 - 5\n",
" ps = [[0] * 301]\n",
" for i in range(1, 301):\n",
" lst = [0]\n",
" for j in range(1, 301):\n",
" lst.append(get(j, i) + ps[i-1][j] + lst[j-1] - ps[i-1][j-1])\n",
" ps.append(lst)\n",
" \n",
" sq = lambda x, y, s: ps[y+s-1][x+s-1] - ps[y-1][x+s-1] - ps[y+s-1][x-1] + ps[y-1][x-1]\n",
" return \",\".join(map(str, max(\n",
" (\n",
" (i, j, s)\n",
" for s in range(1, 301)\n",
" for i in range(1, 302-s)\n",
" for j in range(1, 302-s)\n",
" ), key=lambda k: sq(*k)\n",
" )))\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10.8 s ± 808 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

42
Python/2018/11.py Normal file
View file

@ -0,0 +1,42 @@
from lib import *
input = read_input(2018, 11)
serial = int(input)
get = lambda x, y: ((((x + 10) * y + serial) * (x + 10)) // 100) % 10 - 5
print(
",".join(
map(
str,
max(
((x, y) for x in range(1, 299) for y in range(1, 299)),
key=lambda k: sum(get(k[0] + i, k[1] + j) for i in range(3) for j in range(3)),
),
)
)
)
serial = int(input)
get = lambda x, y: ((((x + 10) * y + serial) * (x + 10)) // 100) % 10 - 5
ps = [[0] * 301]
for i in range(1, 301):
lst = [0]
for j in range(1, 301):
lst.append(get(j, i) + ps[i - 1][j] + lst[j - 1] - ps[i - 1][j - 1])
ps.append(lst)
sq = lambda x, y, s: ps[y + s - 1][x + s - 1] - ps[y - 1][x + s - 1] - ps[y + s - 1][x - 1] + ps[y - 1][x - 1]
print(
",".join(
map(
str,
max(
((i, j, s) for s in range(1, 301) for i in range(1, 302 - s) for j in range(1, 302 - s)),
key=lambda k: sq(*k),
),
)
)
)

View file

@ -1,155 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 12"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 12\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3230"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" state, _, *rules = plines\n",
" state = {i for i, x in enumerate(state.split()[-1]) if x == \"#\"}\n",
" rules = [x.split()[-1] == \"#\" for x in sorted(rules, reverse=True)]\n",
" \n",
" for _ in range(20):\n",
" nums = {k+i-2 for k in state for i in range(5)}\n",
" state = {\n",
" k\n",
" for k in nums\n",
" if rules[sum(((k+i-2) in state) * (2**(4-i)) for i in range(5))]\n",
" }\n",
" return sum(state)\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4400000000304\n"
]
}
],
"source": [
"def solve2():\n",
" state, _, *rules = plines\n",
" state = {i for i, x in enumerate(state.split()[-1]) if x == \"#\"}\n",
" rules = [x.split()[-1] == \"#\" for x in sorted(rules, reverse=True)]\n",
" \n",
" last = None\n",
" for _ in range(200):\n",
" nums = {k+i-2 for k in state for i in range(5)}\n",
" state = {\n",
" k\n",
" for k in nums\n",
" if rules[sum(((k+i-2) in state) * (2**(4-i)) for i in range(5))]\n",
" }\n",
" s = sum(state)\n",
" step = s - last if last is not None else None\n",
" last = s\n",
" print(s + step * (50000000000 - 200))\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

29
Python/2018/12.py Normal file
View file

@ -0,0 +1,29 @@
from lib import *
input = read_input(2018, 12)
lines = input.splitlines()
state, _, *rules = lines
state = {i for i, x in enumerate(state.split()[-1]) if x == "#"}
rules = [x.split()[-1] == "#" for x in sorted(rules, reverse=True)]
for _ in range(20):
nums = {k + i - 2 for k in state for i in range(5)}
state = {k for k in nums if rules[sum(((k + i - 2) in state) * (2 ** (4 - i)) for i in range(5))]}
print(sum(state))
state, _, *rules = lines
state = {i for i, x in enumerate(state.split()[-1]) if x == "#"}
rules = [x.split()[-1] == "#" for x in sorted(rules, reverse=True)]
last = None
for _ in range(200):
nums = {k + i - 2 for k in state for i in range(5)}
state = {k for k in nums if rules[sum(((k + i - 2) in state) * (2 ** (4 - i)) for i in range(5))]}
s = sum(state)
step = s - last if last is not None else None
last = s
print(s + step * (50000000000 - 200))

View file

@ -1,242 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 13"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 13\n",
"\n",
"puzzle = aoc.setup(year, day, strip=False)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'38,57'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" carts = []\n",
" tracks = plines.copy()\n",
" positions = set()\n",
" for y, line in enumerate(tracks):\n",
" for x in range(len(line)):\n",
" c = line[x]\n",
" if c == \"^\":\n",
" carts.append([x, y, 0, -1, 0])\n",
" positions.add((x, y))\n",
" tracks[y] = line = line[:x] + \"|\" + line[x+1:]\n",
" elif c == \"v\":\n",
" carts.append([x, y, 0, 1, 0])\n",
" positions.add((x, y))\n",
" tracks[y] = line = line[:x] + \"|\" + line[x+1:]\n",
" elif c == \"<\":\n",
" carts.append([x, y, -1, 0, 0])\n",
" positions.add((x, y))\n",
" tracks[y] = line = line[:x] + \"-\" + line[x+1:]\n",
" elif c == \">\":\n",
" carts.append([x, y, 1, 0, 0])\n",
" positions.add((x, y))\n",
" tracks[y] = line = line[:x] + \"-\" + line[x+1:]\n",
" \n",
" while True:\n",
" for cart in sorted(carts, key=lambda c: (c[1], c[0])):\n",
" x, y, dx, dy, k = cart\n",
" positions.remove((x, y))\n",
" x += dx\n",
" y += dy\n",
" if (x, y) in positions:\n",
" return f\"{x},{y}\"\n",
" positions.add((x, y))\n",
" \n",
" if tracks[y][x] == \"/\":\n",
" dx, dy = -dy, -dx\n",
" elif tracks[y][x] == \"\\\\\":\n",
" dx, dy = dy, dx\n",
" elif tracks[y][x] == \"+\":\n",
" if k == 0: dx, dy = dy, -dx\n",
" elif k == 2: dx, dy = -dy, dx\n",
" k = (k + 1) % 3\n",
" \n",
" cart[:] = x, y, dx, dy, k\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10.1 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'4,92'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" carts = []\n",
" tracks = plines.copy()\n",
" positions = {}\n",
" crashed = set()\n",
" for y, line in enumerate(tracks):\n",
" for x in range(len(line)):\n",
" c = line[x]\n",
" if c == \"^\":\n",
" carts.append([x*len(tracks)+y, x, y, 0, -1, 0])\n",
" positions[(x, y)] = x*len(tracks)+y\n",
" tracks[y] = line = line[:x] + \"|\" + line[x+1:]\n",
" elif c == \"v\":\n",
" carts.append([x*len(tracks)+y, x, y, 0, 1, 0])\n",
" positions[(x, y)] = x*len(tracks)+y\n",
" tracks[y] = line = line[:x] + \"|\" + line[x+1:]\n",
" elif c == \"<\":\n",
" carts.append([x*len(tracks)+y, x, y, -1, 0, 0])\n",
" positions[(x, y)] = x*len(tracks)+y\n",
" tracks[y] = line = line[:x] + \"-\" + line[x+1:]\n",
" elif c == \">\":\n",
" carts.append([x*len(tracks)+y, x, y, 1, 0, 0])\n",
" positions[(x, y)] = x*len(tracks)+y\n",
" tracks[y] = line = line[:x] + \"-\" + line[x+1:]\n",
"\n",
" while True:\n",
" for cart in sorted(carts, key=lambda c: (c[2], c[1])):\n",
" i, x, y, dx, dy, k = cart\n",
" if i in crashed: continue\n",
" \n",
" positions.pop((x, y))\n",
" x += dx\n",
" y += dy\n",
" if (x, y) in positions:\n",
" crashed.add(i)\n",
" crashed.add(positions.pop((x, y)))\n",
" continue\n",
" positions[(x, y)] = i\n",
" \n",
" if tracks[y][x] == \"/\":\n",
" dx, dy = -dy, -dx\n",
" elif tracks[y][x] == \"\\\\\":\n",
" dx, dy = dy, dx\n",
" elif tracks[y][x] == \"+\":\n",
" if k == 0: dx, dy = dy, -dx\n",
" elif k == 2: dx, dy = -dy, dx\n",
" k = (k + 1) % 3\n",
" \n",
" cart[:] = i, x, y, dx, dy, k\n",
" \n",
" if len(carts) - len(crashed) == 1:\n",
" for i, x, y, *_ in carts:\n",
" if i not in crashed:\n",
" return f\"{x},{y}\"\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"180 ms ± 15.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

110
Python/2018/13.py Normal file
View file

@ -0,0 +1,110 @@
from lib import *
input = read_input(2018, 13)
carts = []
tracks = input.splitlines()
positions = set()
for y, line in enumerate(tracks):
for x in range(len(line)):
c = line[x]
if c == "^":
carts.append([x, y, 0, -1, 0])
positions.add((x, y))
tracks[y] = line = line[:x] + "|" + line[x + 1 :]
elif c == "v":
carts.append([x, y, 0, 1, 0])
positions.add((x, y))
tracks[y] = line = line[:x] + "|" + line[x + 1 :]
elif c == "<":
carts.append([x, y, -1, 0, 0])
positions.add((x, y))
tracks[y] = line = line[:x] + "-" + line[x + 1 :]
elif c == ">":
carts.append([x, y, 1, 0, 0])
positions.add((x, y))
tracks[y] = line = line[:x] + "-" + line[x + 1 :]
while True:
for cart in sorted(carts, key=lambda c: (c[1], c[0])):
x, y, dx, dy, k = cart
positions.remove((x, y))
x += dx
y += dy
if (x, y) in positions:
print(f"{x},{y}")
break
positions.add((x, y))
if tracks[y][x] == "/":
dx, dy = -dy, -dx
elif tracks[y][x] == "\\":
dx, dy = dy, dx
elif tracks[y][x] == "+":
if k == 0:
dx, dy = dy, -dx
elif k == 2:
dx, dy = -dy, dx
k = (k + 1) % 3
cart[:] = x, y, dx, dy, k
else:
continue
break
carts = []
tracks = input.splitlines()
positions = {}
crashed = set()
for y, line in enumerate(tracks):
for x in range(len(line)):
c = line[x]
if c == "^":
carts.append([x * len(tracks) + y, x, y, 0, -1, 0])
positions[(x, y)] = x * len(tracks) + y
tracks[y] = line = line[:x] + "|" + line[x + 1 :]
elif c == "v":
carts.append([x * len(tracks) + y, x, y, 0, 1, 0])
positions[(x, y)] = x * len(tracks) + y
tracks[y] = line = line[:x] + "|" + line[x + 1 :]
elif c == "<":
carts.append([x * len(tracks) + y, x, y, -1, 0, 0])
positions[(x, y)] = x * len(tracks) + y
tracks[y] = line = line[:x] + "-" + line[x + 1 :]
elif c == ">":
carts.append([x * len(tracks) + y, x, y, 1, 0, 0])
positions[(x, y)] = x * len(tracks) + y
tracks[y] = line = line[:x] + "-" + line[x + 1 :]
while True:
for cart in sorted(carts, key=lambda c: (c[2], c[1])):
i, x, y, dx, dy, k = cart
if i in crashed:
continue
positions.pop((x, y))
x += dx
y += dy
if (x, y) in positions:
crashed.add(i)
crashed.add(positions.pop((x, y)))
continue
positions[(x, y)] = i
if tracks[y][x] == "/":
dx, dy = -dy, -dx
elif tracks[y][x] == "\\":
dx, dy = dy, dx
elif tracks[y][x] == "+":
if k == 0:
dx, dy = dy, -dx
elif k == 2:
dx, dy = -dy, dx
k = (k + 1) % 3
cart[:] = i, x, y, dx, dy, k
if len(carts) - len(crashed) == 1:
for i, x, y, *_ in carts:
if i not in crashed:
print(f"{x},{y}")
break
else:
continue
break

View file

@ -1,177 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 14"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 14\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'1052903161'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" r = [3, 7]\n",
" p = 0\n",
" q = 1\n",
" n = int(puzzle)\n",
" while len(r) < n + 10:\n",
" r += [*map(int, str(r[p] + r[q]))]\n",
" p = (p + r[p] + 1) % len(r)\n",
" q = (q + r[q] + 1) % len(r)\n",
" return \"\".join(map(str, r[n:n+10]))\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"414 ms ± 31.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"20165504"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def gen():\n",
" r = [3, 7]\n",
" p = 0\n",
" q = 1\n",
" yield from r\n",
" while True:\n",
" x = [*map(int, str(r[p] + r[q]))]\n",
" yield from x\n",
" r += x\n",
" p = (p + r[p] + 1) % len(r)\n",
" q = (q + r[q] + 1) % len(r)\n",
"\n",
"def solve2():\n",
" n = [*map(int, puzzle)]\n",
" g = gen()\n",
" lst = [i for _, i in zip(n, g)]\n",
" cnt = 0\n",
" for num in g:\n",
" if lst == n:\n",
" return cnt\n",
" lst.pop(0)\n",
" lst.append(num)\n",
" cnt += 1\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"26.1 s ± 955 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

40
Python/2018/14.py Normal file
View file

@ -0,0 +1,40 @@
from lib import *
input = read_input(2018, 14)
r = [3, 7]
p = 0
q = 1
n = int(input)
while len(r) < n + 10:
r += [*map(int, str(r[p] + r[q]))]
p = (p + r[p] + 1) % len(r)
q = (q + r[q] + 1) % len(r)
print("".join(map(str, r[n : n + 10])))
def gen():
r = [3, 7]
p = 0
q = 1
yield from r
while True:
x = [*map(int, str(r[p] + r[q]))]
yield from x
r += x
p = (p + r[p] + 1) % len(r)
q = (q + r[q] + 1) % len(r)
n = [*map(int, input.strip())]
g = gen()
lst = [i for _, i in zip(n, g)]
cnt = 0
for num in g:
if lst == n:
print(cnt)
break
lst.pop(0)
lst.append(num)
cnt += 1

View file

@ -1,340 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 15"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 15\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"237490"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def adj(x, y): return [(x,y-1),(x-1,y),(x+1,y),(x,y+1)]\n",
"\n",
"def solve1():\n",
" entities = {}\n",
" walls = set()\n",
" idx = 0\n",
" for i, line in enumerate(plines):\n",
" for j, c in enumerate(line):\n",
" if c == \"#\": walls.add((j, i))\n",
" elif c != \".\":\n",
" entities[(j, i)] = ((idx, c == \"E\", 200))\n",
" idx += 1\n",
" \n",
" rnd = 0\n",
" while True:\n",
" done = False\n",
" orig = entities.copy()\n",
" for x, y in sorted(entities, key=lambda a: a[::-1]):\n",
" if (x, y) not in entities: continue\n",
" idx, elf, hp = entities[(x, y)]\n",
" if idx != orig[(x, y)][0]: continue\n",
" \n",
" if not any(q[1] != elf for q in entities.values()):\n",
" done = True\n",
" break\n",
"\n",
" in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]\n",
" if not in_range:\n",
" queue = [(0, x, y)]\n",
" visited = set()\n",
" dist = None\n",
" nearest = []\n",
" while queue:\n",
" d, p, q = queue.pop(0)\n",
" \n",
" if (p, q) in visited: continue\n",
" visited.add((p, q))\n",
" \n",
" if any(e[1] != elf for r in adj(p, q) if (e := entities.get(r))):\n",
" if dist is None:\n",
" dist = d\n",
" elif d > dist: break\n",
" nearest.append((p, q))\n",
" \n",
" for r in adj(p, q):\n",
" if r in walls: continue\n",
" if (e := entities.get(r)) and e[1] == elf: continue\n",
" queue.append((d + 1, *r))\n",
" \n",
" if not nearest: continue\n",
" \n",
" target = min(nearest, key=lambda a: a[::-1]) \n",
" \n",
" queue = [(0, *target)]\n",
" visited = set()\n",
" dist = None\n",
" nearest = []\n",
" while queue:\n",
" d, p, q = queue.pop(0)\n",
" \n",
" if (p, q) in visited: continue\n",
" visited.add((p, q))\n",
" \n",
" if (x, y) in adj(p, q):\n",
" if dist is None:\n",
" dist = d\n",
" elif d > dist: break\n",
" nearest.append((p, q))\n",
" \n",
" for r in adj(p, q):\n",
" if r in walls: continue\n",
" if (e := entities.get(r)) and e[1] == elf: continue\n",
" queue.append((d + 1, *r))\n",
"\n",
" if not nearest: continue\n",
" \n",
" g = min(nearest, key=lambda a: a[::-1]) \n",
" \n",
" entities[g] = entities.pop((x, y))\n",
" x, y = g\n",
" \n",
" in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]\n",
" if in_range:\n",
" in_range.sort(key=lambda a: (a[1][2], a[0][::-1]))\n",
" p, (idx2, elf2, hp2) = in_range[0]\n",
" hp2 -= 3\n",
" if hp2 <= 0:\n",
" entities.pop(p)\n",
" else:\n",
" entities[p] = idx2, elf2, hp2\n",
" \n",
" if done: break\n",
" \n",
" rnd += 1\n",
"\n",
" return rnd * sum(e[2] for e in entities.values())\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.33 s ± 164 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"38424"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def simulate(ap):\n",
" entities = {}\n",
" walls = set()\n",
" idx = 0\n",
" for i, line in enumerate(plines):\n",
" for j, c in enumerate(line):\n",
" if c == \"#\": walls.add((j, i))\n",
" elif c != \".\":\n",
" entities[(j, i)] = ((idx, c == \"E\", 200))\n",
" idx += 1\n",
" \n",
" rnd = 0\n",
" while True:\n",
" done = False\n",
" orig = entities.copy()\n",
" for x, y in sorted(entities, key=lambda a: a[::-1]):\n",
" if (x, y) not in entities: continue\n",
" idx, elf, hp = entities[(x, y)]\n",
" if idx != orig[(x, y)][0]: continue\n",
" \n",
" if not any(q[1] != elf for q in entities.values()):\n",
" done = True\n",
" break\n",
"\n",
" in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]\n",
" if not in_range:\n",
" queue = [(0, x, y)]\n",
" visited = set()\n",
" dist = None\n",
" nearest = []\n",
" while queue:\n",
" d, p, q = queue.pop(0)\n",
" \n",
" if (p, q) in visited: continue\n",
" visited.add((p, q))\n",
" \n",
" if any(e[1] != elf for r in adj(p, q) if (e := entities.get(r))):\n",
" if dist is None:\n",
" dist = d\n",
" elif d > dist: break\n",
" nearest.append((p, q))\n",
" \n",
" for r in adj(p, q):\n",
" if r in walls: continue\n",
" if (e := entities.get(r)) and e[1] == elf: continue\n",
" queue.append((d + 1, *r))\n",
" \n",
" if not nearest: continue\n",
" \n",
" target = min(nearest, key=lambda a: a[::-1]) \n",
" \n",
" queue = [(0, *target)]\n",
" visited = set()\n",
" dist = None\n",
" nearest = []\n",
" while queue:\n",
" d, p, q = queue.pop(0)\n",
" \n",
" if (p, q) in visited: continue\n",
" visited.add((p, q))\n",
" \n",
" if (x, y) in adj(p, q):\n",
" if dist is None:\n",
" dist = d\n",
" elif d > dist: break\n",
" nearest.append((p, q))\n",
" \n",
" for r in adj(p, q):\n",
" if r in walls: continue\n",
" if (e := entities.get(r)) and e[1] == elf: continue\n",
" queue.append((d + 1, *r))\n",
"\n",
" if not nearest: continue\n",
" \n",
" g = min(nearest, key=lambda a: a[::-1]) \n",
" \n",
" entities[g] = entities.pop((x, y))\n",
" x, y = g\n",
" \n",
" in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]\n",
" if in_range:\n",
" in_range.sort(key=lambda a: (a[1][2], a[0][::-1]))\n",
" p, (idx2, elf2, hp2) = in_range[0]\n",
" hp2 -= ap if elf else 3\n",
" if hp2 <= 0:\n",
" if elf2: return -1\n",
" entities.pop(p)\n",
" else:\n",
" entities[p] = idx2, elf2, hp2\n",
" \n",
" if done: break\n",
" \n",
" rnd += 1\n",
"\n",
" return rnd * sum(e[2] for e in entities.values())\n",
"\n",
"def solve2():\n",
" ap = 4\n",
" while (res := simulate(ap)) < 0: ap += 1\n",
" return res\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.33 s ± 358 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

233
Python/2018/15.py Normal file
View file

@ -0,0 +1,233 @@
from lib import *
input = read_input(2018, 15)
lines = input.splitlines()
def adj(x, y):
return [(x, y - 1), (x - 1, y), (x + 1, y), (x, y + 1)]
entities = {}
walls = set()
idx = 0
for i, line in enumerate(lines):
for j, c in enumerate(line):
if c == "#":
walls.add((j, i))
elif c != ".":
entities[(j, i)] = (idx, c == "E", 200)
idx += 1
rnd = 0
while True:
done = False
orig = entities.copy()
for x, y in sorted(entities, key=lambda a: a[::-1]):
if (x, y) not in entities:
continue
idx, elf, hp = entities[(x, y)]
if idx != orig[(x, y)][0]:
continue
if not any(q[1] != elf for q in entities.values()):
done = True
break
in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]
if not in_range:
queue = [(0, x, y)]
visited = set()
dist = None
nearest = []
while queue:
d, p, q = queue.pop(0)
if (p, q) in visited:
continue
visited.add((p, q))
if any(e[1] != elf for r in adj(p, q) if (e := entities.get(r))):
if dist is None:
dist = d
elif d > dist:
break
nearest.append((p, q))
for r in adj(p, q):
if r in walls:
continue
if (e := entities.get(r)) and e[1] == elf:
continue
queue.append((d + 1, *r))
if not nearest:
continue
target = min(nearest, key=lambda a: a[::-1])
queue = [(0, *target)]
visited = set()
dist = None
nearest = []
while queue:
d, p, q = queue.pop(0)
if (p, q) in visited:
continue
visited.add((p, q))
if (x, y) in adj(p, q):
if dist is None:
dist = d
elif d > dist:
break
nearest.append((p, q))
for r in adj(p, q):
if r in walls:
continue
if (e := entities.get(r)) and e[1] == elf:
continue
queue.append((d + 1, *r))
if not nearest:
continue
g = min(nearest, key=lambda a: a[::-1])
entities[g] = entities.pop((x, y))
x, y = g
in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]
if in_range:
in_range.sort(key=lambda a: (a[1][2], a[0][::-1]))
p, (idx2, elf2, hp2) = in_range[0]
hp2 -= 3
if hp2 <= 0:
entities.pop(p)
else:
entities[p] = idx2, elf2, hp2
if done:
break
rnd += 1
print(rnd * sum(e[2] for e in entities.values()))
def simulate(ap):
entities = {}
walls = set()
idx = 0
for i, line in enumerate(lines):
for j, c in enumerate(line):
if c == "#":
walls.add((j, i))
elif c != ".":
entities[(j, i)] = (idx, c == "E", 200)
idx += 1
rnd = 0
while True:
done = False
orig = entities.copy()
for x, y in sorted(entities, key=lambda a: a[::-1]):
if (x, y) not in entities:
continue
idx, elf, hp = entities[(x, y)]
if idx != orig[(x, y)][0]:
continue
if not any(q[1] != elf for q in entities.values()):
done = True
break
in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]
if not in_range:
queue = [(0, x, y)]
visited = set()
dist = None
nearest = []
while queue:
d, p, q = queue.pop(0)
if (p, q) in visited:
continue
visited.add((p, q))
if any(e[1] != elf for r in adj(p, q) if (e := entities.get(r))):
if dist is None:
dist = d
elif d > dist:
break
nearest.append((p, q))
for r in adj(p, q):
if r in walls:
continue
if (e := entities.get(r)) and e[1] == elf:
continue
queue.append((d + 1, *r))
if not nearest:
continue
target = min(nearest, key=lambda a: a[::-1])
queue = [(0, *target)]
visited = set()
dist = None
nearest = []
while queue:
d, p, q = queue.pop(0)
if (p, q) in visited:
continue
visited.add((p, q))
if (x, y) in adj(p, q):
if dist is None:
dist = d
elif d > dist:
break
nearest.append((p, q))
for r in adj(p, q):
if r in walls:
continue
if (e := entities.get(r)) and e[1] == elf:
continue
queue.append((d + 1, *r))
if not nearest:
continue
g = min(nearest, key=lambda a: a[::-1])
entities[g] = entities.pop((x, y))
x, y = g
in_range = [(p, q) for p in adj(x, y) if (q := entities.get(p)) and q[1] != elf]
if in_range:
in_range.sort(key=lambda a: (a[1][2], a[0][::-1]))
p, (idx2, elf2, hp2) = in_range[0]
hp2 -= ap if elf else 3
if hp2 <= 0:
if elf2:
return -1
entities.pop(p)
else:
entities[p] = idx2, elf2, hp2
if done:
break
rnd += 1
return rnd * sum(e[2] for e in entities.values())
ap = 4
while (res := simulate(ap)) < 0:
ap += 1
print(res)

View file

@ -1,208 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 16"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 16\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"651"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"opcodes = [\n",
" lambda reg, a, b: reg[a] + reg[b], # addr\n",
" lambda reg, a, b: reg[a] + b, # addi\n",
" lambda reg, a, b: reg[a] * reg[b], # mulr\n",
" lambda reg, a, b: reg[a] * b, # muli\n",
" lambda reg, a, b: reg[a] & reg[b], # banr\n",
" lambda reg, a, b: reg[a] & b, # bani\n",
" lambda reg, a, b: reg[a] | reg[b], # borr\n",
" lambda reg, a, b: reg[a] | b, # bori\n",
" lambda reg, a, b: reg[a], # setr\n",
" lambda reg, a, b: a, # seti\n",
" lambda reg, a, b: a > reg[b], # gtir\n",
" lambda reg, a, b: reg[a] > b, # gtri\n",
" lambda reg, a, b: reg[a] > reg[b], # gtrr\n",
" lambda reg, a, b: a == reg[b], # eqir\n",
" lambda reg, a, b: reg[a] == b, # eqri\n",
" lambda reg, a, b: reg[a] == reg[b], # eqrr\n",
"]\n",
"\n",
"def exec_opcode(reg, op, a, b, c):\n",
" reg[c] = int(op(reg, a, b))\n",
" \n",
"def test_opcode(before, after, op, a, b, c):\n",
" before = [*before]\n",
" exec_opcode(before, op, a, b, c)\n",
" return before == after\n",
"\n",
"def solve1():\n",
" out = 0\n",
" for before, instruction, after in map(str.splitlines, puzzle.split(\"\\n\\n\\n\")[0].split(\"\\n\\n\")):\n",
" before = eval(before.split(\": \")[1])\n",
" _, a, b, c = map(int, instruction.split())\n",
" after = eval(after.split(\": \")[1])\n",
" out += sum(test_opcode(before, after, op, a, b, c) for op in opcodes) >= 3\n",
" return out\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"33.4 ms ± 2.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"706"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" codes = [opcodes.copy() for _ in range(16)]\n",
" m = [None] * 16\n",
" for before, instruction, after in map(str.splitlines, puzzle.split(\"\\n\\n\\n\")[0].split(\"\\n\\n\")):\n",
" before = eval(before.split(\": \")[1])\n",
" op, a, b, c = map(int, instruction.split())\n",
" after = eval(after.split(\": \")[1])\n",
" \n",
" for o in [*codes[op]]:\n",
" if not test_opcode(before, after, o, a, b, c):\n",
" codes[op].remove(o)\n",
" if len(codes[op]) == 1:\n",
" m[op] = codes[op][0]\n",
" \n",
" q = [x for x in m if x]\n",
" while q:\n",
" x = q.pop()\n",
" for i, lst in enumerate(codes):\n",
" if x in lst:\n",
" lst.remove(x)\n",
" if len(lst) == 1:\n",
" m[i] = lst[0]\n",
" q.append(m[i])\n",
"\n",
" reg = [0] * 4\n",
" for line in puzzle.split(\"\\n\\n\\n\\n\")[1].splitlines():\n",
" op, a, b, c = map(int, line.split())\n",
" exec_opcode(reg, m[op], a, b, c)\n",
" return reg[0]\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"31.7 ms ± 7.67 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

75
Python/2018/16.py Normal file
View file

@ -0,0 +1,75 @@
from lib import *
input = read_input(2018, 16)
opcodes = [
lambda reg, a, b: reg[a] + reg[b], # addr
lambda reg, a, b: reg[a] + b, # addi
lambda reg, a, b: reg[a] * reg[b], # mulr
lambda reg, a, b: reg[a] * b, # muli
lambda reg, a, b: reg[a] & reg[b], # banr
lambda reg, a, b: reg[a] & b, # bani
lambda reg, a, b: reg[a] | reg[b], # borr
lambda reg, a, b: reg[a] | b, # bori
lambda reg, a, b: reg[a], # setr
lambda reg, a, b: a, # seti
lambda reg, a, b: a > reg[b], # gtir
lambda reg, a, b: reg[a] > b, # gtri
lambda reg, a, b: reg[a] > reg[b], # gtrr
lambda reg, a, b: a == reg[b], # eqir
lambda reg, a, b: reg[a] == b, # eqri
lambda reg, a, b: reg[a] == reg[b], # eqrr
]
def exec_opcode(reg, op, a, b, c):
reg[c] = int(op(reg, a, b))
def test_opcode(before, after, op, a, b, c):
before = [*before]
exec_opcode(before, op, a, b, c)
return before == after
out = 0
for before, instruction, after in map(str.splitlines, input.split("\n\n\n")[0].split("\n\n")):
before = eval(before.split(": ")[1])
_, a, b, c = map(int, instruction.split())
after = eval(after.split(": ")[1])
out += sum(test_opcode(before, after, op, a, b, c) for op in opcodes) >= 3
print(out)
codes = [opcodes.copy() for _ in range(16)]
m = [None] * 16
for before, instruction, after in map(str.splitlines, input.split("\n\n\n")[0].split("\n\n")):
before = eval(before.split(": ")[1])
op, a, b, c = map(int, instruction.split())
after = eval(after.split(": ")[1])
for o in [*codes[op]]:
if not test_opcode(before, after, o, a, b, c):
codes[op].remove(o)
if len(codes[op]) == 1:
m[op] = codes[op][0]
q = [x for x in m if x]
while q:
x = q.pop()
for i, lst in enumerate(codes):
if x in lst:
lst.remove(x)
if len(lst) == 1:
m[i] = lst[0]
q.append(m[i])
reg = [0] * 4
for line in input.split("\n\n\n\n")[1].splitlines():
op, a, b, c = map(int, line.split())
exec_opcode(reg, m[op], a, b, c)
print(reg[0])

View file

@ -1,260 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 17"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 17\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"37858"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" clay = set()\n",
" miny = 1e1337\n",
" maxy = 0\n",
" for line in plines:\n",
" a, b = line.split(\", \")\n",
" a = int(a.split(\"=\")[1])\n",
" b1, b2 = map(int, b.split(\"=\")[1].split(\"..\"))\n",
" for i in range(b1, b2+1):\n",
" if line[0] == \"x\": x, y = a, i\n",
" else: x, y = i, a\n",
" clay.add((x, y))\n",
" miny = min(y, miny)\n",
" maxy = max(y, maxy)\n",
" \n",
" reachable = set()\n",
" water = set()\n",
" dp = {}\n",
" def flow(x, y):\n",
" if y > maxy: return False\n",
" if (x, y) in clay: return True\n",
" if (x, y) in dp:\n",
" return dp[(x, y)]\n",
" \n",
" reachable.add((x, y))\n",
" \n",
" if not flow(x, y + 1):\n",
" dp[(x, y)] = False\n",
" return False\n",
"\n",
" add = set()\n",
" ok = True\n",
" \n",
" k = x\n",
" while (k, y) not in clay:\n",
" add.add((k, y))\n",
" if not flow(k, y + 1):\n",
" ok = False\n",
" break\n",
" k -= 1\n",
" \n",
" k = x\n",
" while (k, y) not in clay:\n",
" add.add((k, y))\n",
" if not flow(k, y + 1):\n",
" ok = False\n",
" break\n",
" k += 1\n",
" \n",
" reachable.update(add)\n",
" if ok: water.update(add)\n",
" \n",
" dp[(x, y)] = ok\n",
" return ok\n",
" \n",
" flow(500, 0)\n",
" \n",
" return sum((x, y) != (500, 0) and y in range(miny, maxy+1) for x, y in reachable)\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.83 s ± 283 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"30410"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" clay = set()\n",
" miny = 1e1337\n",
" maxy = 0\n",
" for line in plines:\n",
" a, b = line.split(\", \")\n",
" a = int(a.split(\"=\")[1])\n",
" b1, b2 = map(int, b.split(\"=\")[1].split(\"..\"))\n",
" for i in range(b1, b2+1):\n",
" if line[0] == \"x\": x, y = a, i\n",
" else: x, y = i, a\n",
" clay.add((x, y))\n",
" miny = min(y, miny)\n",
" maxy = max(y, maxy)\n",
" \n",
" reachable = set()\n",
" water = set()\n",
" dp = {}\n",
" def flow(x, y):\n",
" if y > maxy: return False\n",
" if (x, y) in clay: return True\n",
" if (x, y) in dp:\n",
" return dp[(x, y)]\n",
" \n",
" reachable.add((x, y))\n",
" \n",
" if not flow(x, y + 1):\n",
" dp[(x, y)] = False\n",
" return False\n",
"\n",
" add = set()\n",
" ok = True\n",
" \n",
" k = x\n",
" while (k, y) not in clay:\n",
" add.add((k, y))\n",
" if not flow(k, y + 1):\n",
" ok = False\n",
" break\n",
" k -= 1\n",
" \n",
" k = x\n",
" while (k, y) not in clay:\n",
" add.add((k, y))\n",
" if not flow(k, y + 1):\n",
" ok = False\n",
" break\n",
" k += 1\n",
" \n",
" reachable.update(add)\n",
" if ok: water.update(add)\n",
" \n",
" dp[(x, y)] = ok\n",
" return ok\n",
" \n",
" flow(500, 0)\n",
" \n",
" return len(water)\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.71 s ± 239 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

138
Python/2018/17.py Normal file
View file

@ -0,0 +1,138 @@
import sys
from lib import *
sys.setrecursionlimit(10000)
input = read_input(2018, 17)
lines = input.splitlines()
clay = set()
miny = 1e1337
maxy = 0
for line in lines:
a, b = line.split(", ")
a = int(a.split("=")[1])
b1, b2 = map(int, b.split("=")[1].split(".."))
for i in range(b1, b2 + 1):
if line[0] == "x":
x, y = a, i
else:
x, y = i, a
clay.add((x, y))
miny = min(y, miny)
maxy = max(y, maxy)
reachable = set()
water = set()
dp = {}
def flow(x, y):
if y > maxy:
return False
if (x, y) in clay:
return True
if (x, y) in dp:
return dp[(x, y)]
reachable.add((x, y))
if not flow(x, y + 1):
dp[(x, y)] = False
return False
add = set()
ok = True
k = x
while (k, y) not in clay:
add.add((k, y))
if not flow(k, y + 1):
ok = False
break
k -= 1
k = x
while (k, y) not in clay:
add.add((k, y))
if not flow(k, y + 1):
ok = False
break
k += 1
reachable.update(add)
if ok:
water.update(add)
dp[(x, y)] = ok
return ok
flow(500, 0)
print(sum((x, y) != (500, 0) and y in range(miny, maxy + 1) for x, y in reachable))
clay = set()
miny = 1e1337
maxy = 0
for line in lines:
a, b = line.split(", ")
a = int(a.split("=")[1])
b1, b2 = map(int, b.split("=")[1].split(".."))
for i in range(b1, b2 + 1):
if line[0] == "x":
x, y = a, i
else:
x, y = i, a
clay.add((x, y))
miny = min(y, miny)
maxy = max(y, maxy)
reachable = set()
water = set()
dp = {}
def flow(x, y):
if y > maxy:
return False
if (x, y) in clay:
return True
if (x, y) in dp:
return dp[(x, y)]
reachable.add((x, y))
if not flow(x, y + 1):
dp[(x, y)] = False
return False
add = set()
ok = True
k = x
while (k, y) not in clay:
add.add((k, y))
if not flow(k, y + 1):
ok = False
break
k -= 1
k = x
while (k, y) not in clay:
add.add((k, y))
if not flow(k, y + 1):
ok = False
break
k += 1
reachable.update(add)
if ok:
water.update(add)
dp[(x, y)] = ok
return ok
flow(500, 0)
print(len(water))

View file

@ -1,193 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 18"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 18\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"594712"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def cntAdj(grid, y, x, t):\n",
" return sum(grid[i][j] == t for i in range(y-1, y+2) for j in range(x-1, x+2) if (i, j) != (y, x) and i in range(len(grid)) and j in range(len(grid[i])))\n",
"\n",
"def solve1():\n",
" grid = plines\n",
" for _ in range(10):\n",
" new_grid = []\n",
" for i, line in enumerate(grid):\n",
" new_line = \"\"\n",
" for j, c in enumerate(line):\n",
" if c == \".\" and cntAdj(grid, i, j, \"|\") >= 3: new_line += \"|\"\n",
" elif c == \"|\" and cntAdj(grid, i, j, \"#\") >= 3: new_line += \"#\"\n",
" elif c == \"#\" and not (cntAdj(grid, i, j, \"#\") >= 1 and cntAdj(grid, i, j, \"|\") >= 1): new_line += \".\"\n",
" else: new_line += c\n",
" new_grid.append(new_line)\n",
" grid = new_grid\n",
" \n",
" a = sum(line.count(\"|\") for line in grid)\n",
" b = sum(line.count(\"#\") for line in grid)\n",
" return a * b\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"294 ms ± 69.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"203138"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def next_iteration(grid):\n",
" new_grid = []\n",
" for i, line in enumerate(grid):\n",
" new_line = \"\"\n",
" for j, c in enumerate(line):\n",
" if c == \".\" and cntAdj(grid, i, j, \"|\") >= 3: new_line += \"|\"\n",
" elif c == \"|\" and cntAdj(grid, i, j, \"#\") >= 3: new_line += \"#\"\n",
" elif c == \"#\" and not (cntAdj(grid, i, j, \"#\") >= 1 and cntAdj(grid, i, j, \"|\") >= 1): new_line += \".\"\n",
" else: new_line += c\n",
" new_grid.append(new_line)\n",
" return new_grid\n",
"\n",
"def solve2():\n",
" grid = plines\n",
" seen = {}\n",
" i = 0\n",
" while tuple(grid) not in seen:\n",
" seen[tuple(grid)] = i\n",
" grid = next_iteration(grid)\n",
" i += 1\n",
" \n",
" cycle = i - seen[tuple(grid)]\n",
" \n",
" for _ in range((1000000000 - i) % cycle):\n",
" grid = next_iteration(grid)\n",
" \n",
" a = sum(line.count(\"|\") for line in grid)\n",
" b = sum(line.count(\"#\") for line in grid)\n",
" return a * b\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"13.1 s ± 634 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

68
Python/2018/18.py Normal file
View file

@ -0,0 +1,68 @@
from lib import *
input = read_input(2018, 18)
def cntAdj(grid, y, x, t):
return sum(
grid[i][j] == t
for i in range(y - 1, y + 2)
for j in range(x - 1, x + 2)
if (i, j) != (y, x) and i in range(len(grid)) and j in range(len(grid[i]))
)
grid = input.splitlines()
for _ in range(10):
new_grid = []
for i, line in enumerate(grid):
new_line = ""
for j, c in enumerate(line):
if c == "." and cntAdj(grid, i, j, "|") >= 3:
new_line += "|"
elif c == "|" and cntAdj(grid, i, j, "#") >= 3:
new_line += "#"
elif c == "#" and not (cntAdj(grid, i, j, "#") >= 1 and cntAdj(grid, i, j, "|") >= 1):
new_line += "."
else:
new_line += c
new_grid.append(new_line)
grid = new_grid
a = sum(line.count("|") for line in grid)
b = sum(line.count("#") for line in grid)
print(a * b)
def next_iteration(grid):
new_grid = []
for i, line in enumerate(grid):
new_line = ""
for j, c in enumerate(line):
if c == "." and cntAdj(grid, i, j, "|") >= 3:
new_line += "|"
elif c == "|" and cntAdj(grid, i, j, "#") >= 3:
new_line += "#"
elif c == "#" and not (cntAdj(grid, i, j, "#") >= 1 and cntAdj(grid, i, j, "|") >= 1):
new_line += "."
else:
new_line += c
new_grid.append(new_line)
return new_grid
grid = input.splitlines()
seen = {}
i = 0
while tuple(grid) not in seen:
seen[tuple(grid)] = i
grid = next_iteration(grid)
i += 1
cycle = i - seen[tuple(grid)]
for _ in range((1000000000 - i) % cycle):
grid = next_iteration(grid)
a = sum(line.count("|") for line in grid)
b = sum(line.count("#") for line in grid)
print(a * b)

View file

@ -1,242 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 19"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 19\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"opcodes = {\n",
" \"addr\": lambda reg, a, b: reg[a] + reg[b], # addr\n",
" \"addi\": lambda reg, a, b: reg[a] + b, # addi\n",
" \"mulr\": lambda reg, a, b: reg[a] * reg[b], # mulr\n",
" \"muli\": lambda reg, a, b: reg[a] * b, # muli\n",
" \"banr\": lambda reg, a, b: reg[a] & reg[b], # banr\n",
" \"bani\": lambda reg, a, b: reg[a] & b, # bani\n",
" \"borr\": lambda reg, a, b: reg[a] | reg[b], # borr\n",
" \"bori\": lambda reg, a, b: reg[a] | b, # bori\n",
" \"setr\": lambda reg, a, b: reg[a], # setr\n",
" \"seti\": lambda reg, a, b: a, # seti\n",
" \"gtir\": lambda reg, a, b: a > reg[b], # gtir\n",
" \"gtri\": lambda reg, a, b: reg[a] > b, # gtri\n",
" \"gtrr\": lambda reg, a, b: reg[a] > reg[b], # gtrr\n",
" \"eqir\": lambda reg, a, b: a == reg[b], # eqir\n",
" \"eqri\": lambda reg, a, b: reg[a] == b, # eqri\n",
" \"eqrr\": lambda reg, a, b: reg[a] == reg[b], # eqrr\n",
"}\n",
"\n",
"def exec_opcode(reg, op, a, b, c):\n",
" reg[c] = int(opcodes[op](reg, a, b))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1568"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" ip, *instructions = plines\n",
" ip = int(ip.split()[1])\n",
" reg = [0] * 6\n",
" while reg[ip] in range(len(instructions)):\n",
" op, a, b, c = instructions[reg[ip]].split()\n",
" exec_opcode(reg, op, *map(int, [a,b,c]))\n",
" reg[ip] += 1\n",
" return reg[0]\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"13.5 s ± 619 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"000| ip += 16\n",
"001| r5 = 1\n",
"002| r3 = 1\n",
"003| r4 = r5 * r3\n",
"004| r4 = r4 == r1\n",
"005| ip += r4\n",
"006| ip += 1\n",
"007| r0 += r5\n",
"008| r3 += 1\n",
"009| r4 = r3 > r1\n",
"010| ip += r4\n",
"011| ip = 2\n",
"012| r5 += 1\n",
"013| r4 = r5 > r1\n",
"014| ip += r4\n",
"015| ip = 1\n",
"016| ip *= ip\n",
"017| r1 += 2\n",
"018| r1 *= r1\n",
"019| r1 *= ip\n",
"020| r1 *= 11\n",
"021| r4 += 2\n",
"022| r4 *= ip\n",
"023| r4 += 12\n",
"024| r1 += r4\n",
"025| ip += r0\n",
"026| ip = 0\n",
"027| r4 = ip\n",
"028| r4 *= ip\n",
"029| r4 += ip\n",
"030| r4 *= ip\n",
"031| r4 *= 14\n",
"032| r4 *= ip\n",
"033| r1 += r4\n",
"034| r0 = 0\n",
"035| ip = 0\n"
]
}
],
"source": [
"ip, *instructions = plines\n",
"ip = int(ip.split()[1])\n",
"\n",
"reg = lambda i: \"ip\" if i == ip else f\"r{i}\"\n",
"\n",
"for i, (op, a, b, c) in enumerate(map(str.split, instructions)):\n",
" a, b, c = map(int, [a, b, c])\n",
" if op[:2] in [\"eq\", \"gt\"]:\n",
" print(f\"{i:03}| {reg(c)} = {reg(a) if op[2]=='r' else a} { {'eq':'==','gt':'>'}[op[:2]]} {reg(b) if op[3]=='r' else b}\")\n",
" elif op[:3] == \"set\":\n",
" print(f\"{i:03}| {reg(c)} = {reg(a) if op[-1]=='r' else a}\")\n",
" else:\n",
" if a == c:\n",
" print(f\"{i:03}| {reg(c)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]}= {reg(b) if op[-1]=='r' else b}\") \n",
" elif b == c and op[-1] == \"r\":\n",
" print(f\"{i:03}| {reg(c)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]}= {reg(a)}\") \n",
" else:\n",
" print(f\"{i:03}| {reg(c)} = {reg(a)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]} {reg(b) if op[-1]=='r' else b}\") \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"19030032"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r1 = 2 * 2 * 19 * 11 + 2 * 22 + 12 + (27 * 28 + 29) * 30 * 14 * 32\n",
"r0 = 0\n",
"\n",
"for r5 in range(1, r1 + 1):\n",
" if r1 % r5 == 0: r0 += r5\n",
"# for r3 in range(1, r1 + 1):\n",
"# if r3 == r1 / r5: r0 += r5\n",
"\n",
"r0"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

48
Python/2018/19.py Normal file
View file

@ -0,0 +1,48 @@
from lib import *
input = read_input(2018, 19)
lines = input.splitlines()
opcodes = {
"addr": lambda reg, a, b: reg[a] + reg[b],
"addi": lambda reg, a, b: reg[a] + b,
"mulr": lambda reg, a, b: reg[a] * reg[b],
"muli": lambda reg, a, b: reg[a] * b,
"banr": lambda reg, a, b: reg[a] & reg[b],
"bani": lambda reg, a, b: reg[a] & b,
"borr": lambda reg, a, b: reg[a] | reg[b],
"bori": lambda reg, a, b: reg[a] | b,
"setr": lambda reg, a, b: reg[a],
"seti": lambda reg, a, b: a,
"gtir": lambda reg, a, b: a > reg[b],
"gtri": lambda reg, a, b: reg[a] > b,
"gtrr": lambda reg, a, b: reg[a] > reg[b],
"eqir": lambda reg, a, b: a == reg[b],
"eqri": lambda reg, a, b: reg[a] == b,
"eqrr": lambda reg, a, b: reg[a] == reg[b],
}
def exec_opcode(reg, op, a, b, c):
reg[c] = int(opcodes[op](reg, a, b))
ip, *instructions = lines
ip = int(ip.split()[1])
reg = [0] * 6
while reg[ip] in range(len(instructions)):
op, a, b, c = instructions[reg[ip]].split()
exec_opcode(reg, op, *map(int, [a, b, c]))
reg[ip] += 1
print(reg[0])
r1 = 2 * 2 * 19 * 11 + 2 * 22 + 12 + (27 * 28 + 29) * 30 * 14 * 32
r0 = 0
for r5 in range(1, r1 + 1):
if r1 % r5 == 0:
r0 += r5
print(r0)

View file

@ -1,239 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 20"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 20\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3545"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def parse_regex(regex):\n",
" regex = regex.strip(\"^$\")\n",
" stack = [[]]\n",
" \n",
" for c in regex:\n",
" if c == \"(\":\n",
" stack.append([])\n",
" stack.append([])\n",
" elif c == \")\":\n",
" x = stack.pop()\n",
" y = stack.pop()\n",
" y.append(x)\n",
" stack[-1].append(tuple(y))\n",
" elif c == \"|\":\n",
" x = stack.pop()\n",
" stack[-1].append(x)\n",
" stack.append([])\n",
" else:\n",
" stack[-1].append(c)\n",
" \n",
" return stack[0]\n",
"\n",
"dp = set()\n",
"\n",
"def traverse(graph, regex, x, y, decisions=None, pop_after=None):\n",
" decisions = decisions or ()\n",
" if (x, y, decisions) in dp: return\n",
" dp.add((x, y, decisions))\n",
" \n",
" i = 0\n",
" while i < len(regex):\n",
" if i == pop_after: decisions = (*decisions[:-1], None)\n",
" \n",
" elem = regex[i]\n",
" prev = x, y\n",
" if isinstance(elem, tuple):\n",
" for j, option in enumerate(elem):\n",
" traverse(graph, option + regex[i+1:], x, y, (*decisions, j), len(option))\n",
" break\n",
" elif elem == \"N\":\n",
" y -= 1\n",
" elif elem == \"E\":\n",
" x += 1\n",
" elif elem == \"S\":\n",
" y += 1\n",
" elif elem == \"W\":\n",
" x -= 1\n",
" \n",
" graph.setdefault(prev, set()).add((x, y))\n",
" graph.setdefault((x, y), set()).add(prev)\n",
" \n",
" i += 1\n",
"\n",
"def solve1():\n",
" dp.clear()\n",
" regex = parse_regex(puzzle)\n",
" graph = {}\n",
" traverse(graph, regex, 0, 0)\n",
" \n",
" queue = [(0, 0, 0)]\n",
" visited = set()\n",
" out = 0\n",
" while queue:\n",
" d, x, y = queue.pop(0)\n",
" \n",
" if (x, y) in visited: continue\n",
" visited.add((x, y))\n",
" \n",
" out = max(out, d)\n",
" \n",
" for p, q in graph.get((x, y), []):\n",
" if (p, q) not in visited: queue.append((d+1, p, q))\n",
" \n",
" return out\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"67.1 ms ± 12.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"7838"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" dp.clear()\n",
" regex = parse_regex(puzzle)\n",
" graph = {}\n",
" traverse(graph, regex, 0, 0)\n",
" \n",
" queue = [(0, 0, 0)]\n",
" visited = set()\n",
" out = 0\n",
" while queue:\n",
" d, x, y = queue.pop(0)\n",
" \n",
" if (x, y) in visited: continue\n",
" visited.add((x, y))\n",
" \n",
" if d >= 1000: out += 1\n",
" \n",
" for p, q in graph.get((x, y), []):\n",
" if (p, q) not in visited: queue.append((d+1, p, q))\n",
" \n",
" return out\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"65 ms ± 14.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

101
Python/2018/20.py Normal file
View file

@ -0,0 +1,101 @@
from lib import *
input = read_input(2018, 20)
def parse_regex(regex):
regex = regex.strip("^$")
stack = [[]]
for c in regex:
if c == "(":
stack.append([])
stack.append([])
elif c == ")":
x = stack.pop()
y = stack.pop()
y.append(x)
stack[-1].append(tuple(y))
elif c == "|":
x = stack.pop()
stack[-1].append(x)
stack.append([])
else:
stack[-1].append(c)
return stack[0]
dp = set()
def traverse(graph, regex, x, y, decisions=None, pop_after=None):
decisions = decisions or ()
if (x, y, decisions) in dp:
return
dp.add((x, y, decisions))
i = 0
while i < len(regex):
if i == pop_after:
decisions = (*decisions[:-1], None)
elem = regex[i]
prev = x, y
if isinstance(elem, tuple):
for j, option in enumerate(elem):
traverse(graph, option + regex[i + 1 :], x, y, (*decisions, j), len(option))
break
elif elem == "N":
y -= 1
elif elem == "E":
x += 1
elif elem == "S":
y += 1
elif elem == "W":
x -= 1
graph.setdefault(prev, set()).add((x, y))
graph.setdefault((x, y), set()).add(prev)
i += 1
regex = parse_regex(input)
graph = {}
traverse(graph, regex, 0, 0)
queue = [(0, 0, 0)]
visited = set()
out = 0
while queue:
d, x, y = queue.pop(0)
if (x, y) in visited:
continue
visited.add((x, y))
out = max(out, d)
for p, q in graph.get((x, y), []):
if (p, q) not in visited:
queue.append((d + 1, p, q))
print(out)
dp.clear()
regex = parse_regex(input)
graph = {}
traverse(graph, regex, 0, 0)
queue = [(0, 0, 0)]
visited = set()
out = 0
while queue:
d, x, y = queue.pop(0)
if (x, y) in visited:
continue
visited.add((x, y))
if d >= 1000:
out += 1
for p, q in graph.get((x, y), []):
if (p, q) not in visited:
queue.append((d + 1, p, q))
print(out)

View file

@ -1,263 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 21"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 21\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"000| r1 = 123\n",
"001| r1 &= 456\n",
"002| r1 = r1 == 72\n",
"003| ip += r1\n",
"004| ip = 0\n",
"005| r1 = 0\n",
"006| r5 = r1 | 65536\n",
"007| r1 = 8586263\n",
"008| r2 = r5 & 255\n",
"009| r1 += r2\n",
"010| r1 &= 16777215\n",
"011| r1 *= 65899\n",
"012| r1 &= 16777215\n",
"013| r2 = 256 > r5\n",
"014| ip += r2\n",
"015| ip += 1\n",
"016| ip = 27\n",
"017| r2 = 0\n",
"018| r3 = r2 + 1\n",
"019| r3 *= 256\n",
"020| r3 = r3 > r5\n",
"021| ip += r3\n",
"022| ip += 1\n",
"023| ip = 25\n",
"024| r2 += 1\n",
"025| ip = 17\n",
"026| r5 = r2\n",
"027| ip = 7\n",
"028| r2 = r1 == r0\n",
"029| ip += r2\n",
"030| ip = 5\n"
]
}
],
"source": [
"ip, *instructions = plines\n",
"ip = int(ip.split()[1])\n",
"\n",
"reg = lambda i: \"ip\" if i == ip else f\"r{i}\"\n",
"\n",
"for i, (op, a, b, c) in enumerate(map(str.split, instructions)):\n",
" a, b, c = map(int, [a, b, c])\n",
" if op[:2] in [\"eq\", \"gt\"]:\n",
" print(f\"{i:03}| {reg(c)} = {reg(a) if op[2]=='r' else a} { {'eq':'==','gt':'>'}[op[:2]]} {reg(b) if op[3]=='r' else b}\")\n",
" elif op[:3] == \"set\":\n",
" print(f\"{i:03}| {reg(c)} = {reg(a) if op[-1]=='r' else a}\")\n",
" else:\n",
" if a == c:\n",
" print(f\"{i:03}| {reg(c)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]}= {reg(b) if op[-1]=='r' else b}\") \n",
" elif b == c and op[-1] == \"r\":\n",
" print(f\"{i:03}| {reg(c)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]}= {reg(a)}\") \n",
" else:\n",
" print(f\"{i:03}| {reg(c)} = {reg(a)} { {'add':'+','mul':'*','ban':'&','bor':'|'}[op[:3]]} {reg(b) if op[-1]=='r' else b}\") "
]
},
{
"cell_type": "raw",
"metadata": {},
"source": [
"assert 123 & 456 == 72\n",
"\n",
"r1 = 0\n",
"\n",
"while True:\n",
" r5 = r1 | 65536\n",
" r1 = 8586263\n",
"\n",
" while r5:\n",
" r1 += r5 & 255\n",
" r1 &= 16777215\n",
" r1 *= 65899\n",
" r1 &= 16777215\n",
" \n",
" r5 //= 256\n",
"\n",
" if r1 == r0: break"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5970144"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" r1 = 0\n",
" r5 = r1 | 65536\n",
" r1 = 8586263\n",
"\n",
" while r5:\n",
" r1 += r5 & 255\n",
" r1 &= 16777215\n",
" r1 *= 65899\n",
" r1 &= 16777215\n",
"\n",
" r5 //= 256\n",
" return r1\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.08 µs ± 60.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"13943296"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve2():\n",
" r1 = 0\n",
" seen = set()\n",
" out = r1\n",
" while r1 not in seen:\n",
" out = r1\n",
" seen.add(r1)\n",
" r5 = r1 | 65536\n",
" r1 = 8586263\n",
"\n",
" while r5:\n",
" r1 += r5 & 255\n",
" r1 &= 16777215\n",
" r1 *= 65899\n",
" r1 &= 16777215\n",
"\n",
" r5 //= 256\n",
"\n",
" return out\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"13.4 ms ± 877 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

28
Python/2018/21.py Normal file
View file

@ -0,0 +1,28 @@
r1 = 0
r5 = r1 | 65536
r1 = 8586263
while r5:
r1 += r5 & 255
r1 &= 16777215
r1 *= 65899
r1 &= 16777215
r5 //= 256
print(r1)
r1 = 0
seen = set()
out = r1
while r1 not in seen:
out = r1
seen.add(r1)
r5 = r1 | 65536
r1 = 8586263
while r5:
r1 += r5 & 255
r1 &= 16777215
r1 *= 65899
r1 &= 16777215
r5 //= 256
print(out)

View file

@ -1,183 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 22"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 22\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"7743"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"depth = int(plines[0].split()[1])\n",
"tx, ty = map(int, plines[1].split()[1].split(\",\"))\n",
"\n",
"dp = {}\n",
"def get_geologic_index(x, y):\n",
" if (x, y) == (tx, ty): return 0\n",
" if y == 0: return x * 16807\n",
" if x == 0: return y * 48271\n",
" if (x, y) not in dp: dp[(x, y)] = get_erosion_level(x-1, y) * get_erosion_level(x, y-1)\n",
" return dp[(x, y)]\n",
"\n",
"def get_erosion_level(x, y):\n",
" return (get_geologic_index(x, y) + depth) % 20183\n",
"\n",
"def solve1():\n",
" return sum(get_erosion_level(x, y) % 3 for y in range(ty+1) for x in range(tx+1))\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.58 ms ± 456 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1029"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import heapq\n",
"\n",
"def solve2():\n",
" queue = [(0, 0, 0, 1)]\n",
" visited = set()\n",
" while queue:\n",
" d, x, y, e = heapq.heappop(queue)\n",
" \n",
" if (x, y, e) in visited: continue\n",
" visited.add((x, y, e))\n",
" \n",
" if (x, y, e) == (tx, ty, 1):\n",
" return d\n",
" \n",
" t = get_erosion_level(x, y) % 3\n",
" \n",
" heapq.heappush(queue, (d + 7, x, y, (-e-t)%3))\n",
" \n",
" for p, q in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:\n",
" if p < 0 or q < 0: continue\n",
" t = get_erosion_level(p, q) % 3\n",
" if t == e: continue\n",
" heapq.heappush(queue, (d + 1, p, q, e))\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"18.4 s ± 659 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

56
Python/2018/22.py Normal file
View file

@ -0,0 +1,56 @@
from lib import *
input = read_input(2018, 22)
lines = input.splitlines()
depth = int(lines[0].split()[1])
tx, ty = map(int, lines[1].split()[1].split(","))
dp = {}
def get_geologic_index(x, y):
if (x, y) == (tx, ty):
return 0
if y == 0:
return x * 16807
if x == 0:
return y * 48271
if (x, y) not in dp:
dp[(x, y)] = get_erosion_level(x - 1, y) * get_erosion_level(x, y - 1)
return dp[(x, y)]
def get_erosion_level(x, y):
return (get_geologic_index(x, y) + depth) % 20183
print(sum(get_erosion_level(x, y) % 3 for y in range(ty + 1) for x in range(tx + 1)))
queue = [(0, 0, 0, 1)]
visited = set()
while queue:
d, x, y, e = heapq.heappop(queue)
if (x, y, e) in visited:
continue
visited.add((x, y, e))
if (x, y, e) == (tx, ty, 1):
print(d)
break
t = get_erosion_level(x, y) % 3
heapq.heappush(queue, (d + 7, x, y, (-e - t) % 3))
for p, q in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
if p < 0 or q < 0:
continue
t = get_erosion_level(p, q) % 3
if t == e:
continue
heapq.heappush(queue, (d + 1, p, q, e))

View file

@ -1,185 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 23"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 23\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"730"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" bots = []\n",
" for pos, r in map(str.split, plines):\n",
" x, y, z = map(int, pos.split(\"<\")[1].strip(\">,\").split(\",\"))\n",
" r = int(r.split(\"=\")[1])\n",
" bots.append((x, y, z, r))\n",
" \n",
" sx, sy, sz, sr = max(bots, key=lambda a: a[3])\n",
" return sum(abs(x-sx)+abs(y-sy)+abs(z-sz) <= sr for x, y, z, _ in bots)\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2.38 ms ± 225 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"48202279"
],
"text/plain": [
"48202279"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from z3 import *\n",
"\n",
"def solve2():\n",
" bots = []\n",
" for pos, r in map(str.split, plines):\n",
" x, y, z = map(int, pos.split(\"<\")[1].strip(\">,\").split(\",\"))\n",
" r = int(r.split(\"=\")[1])\n",
" bots.append((x, y, z, r))\n",
"\n",
" zabs = lambda x: If(x >= 0, x, -x)\n",
"\n",
" x, y, z = Ints(\"x y z\")\n",
" in_ranges = [Int(f\"in_range_{i}\") for i in range(len(bots))]\n",
" range_count = Int(\"sum\")\n",
" \n",
" o = Optimize()\n",
" for (nx, ny, nz, nr), ir in zip(bots, in_ranges):\n",
" o.add(ir == If(zabs(x - nx) + zabs(y - ny) + zabs(z - nz) <= nr, 1, 0))\n",
"\n",
" o.add(range_count == sum(in_ranges))\n",
" \n",
" dist_from_zero = Int(\"dist\")\n",
" o.add(dist_from_zero == zabs(x) + zabs(y) + zabs(z))\n",
" \n",
" h1 = o.maximize(range_count)\n",
" h2 = o.minimize(dist_from_zero)\n",
"\n",
" o.check()\n",
" return o.lower(h2)\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1min 31s ± 15.4 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

39
Python/2018/23.py Normal file
View file

@ -0,0 +1,39 @@
from lib import *
input = read_input(2018, 23)
lines = input.splitlines()
bots = []
for pos, r in map(str.split, lines):
x, y, z = map(int, pos.split("<")[1].strip(">,").split(","))
r = int(r.split("=")[1])
bots.append((x, y, z, r))
sx, sy, sz, sr = max(bots, key=lambda a: a[3])
print(sum(abs(x - sx) + abs(y - sy) + abs(z - sz) <= sr for x, y, z, _ in bots))
bots = []
for pos, r in map(str.split, lines):
x, y, z = map(int, pos.split("<")[1].strip(">,").split(","))
r = int(r.split("=")[1])
bots.append((x, y, z, r))
zabs = lambda x: z3.If(x >= 0, x, -x)
x, y, z = z3.Ints("x y z")
in_ranges = [z3.Int(f"in_range_{i}") for i in range(len(bots))]
range_count = z3.Int("sum")
o = z3.Optimize()
for (nx, ny, nz, nr), ir in zip(bots, in_ranges):
o.add(ir == z3.If(zabs(x - nx) + zabs(y - ny) + zabs(z - nz) <= nr, 1, 0))
o.add(range_count == sum(in_ranges))
dist_from_zero = z3.Int("dist")
o.add(dist_from_zero == zabs(x) + zabs(y) + zabs(z))
h1 = o.maximize(range_count)
h2 = o.minimize(dist_from_zero)
o.check()
print(o.lower(h2))

View file

@ -1,253 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 24"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 24\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"import re\n",
"\n",
"@dataclass\n",
"class Group:\n",
" army: int\n",
" units: int\n",
" hp: int\n",
" ap: int\n",
" at: str\n",
" init: int\n",
" weak: set[str]\n",
" immune: set[str]\n",
" \n",
" def __hash__(self): return id(self)\n",
" \n",
" @staticmethod\n",
" def parse(army, line, boost=0):\n",
" units, hp, _, extra, ap, at, init = re.match(r\"^(\\d+) units each with (\\d+) hit points( \\((.*)\\))? with an attack that does (\\d+) (\\w+) damage at initiative (\\d+)$\", line).groups()\n",
" \n",
" weak = set()\n",
" immune = set()\n",
" for part in extra.split(\"; \") if extra else []:\n",
" t, _, *xs = part.split()\n",
" {\"weak\": weak, \"immune\": immune}[t].update(x.strip(\",\") for x in xs)\n",
" \n",
" return Group(army, int(units), int(hp), int(ap) + boost, at, int(init), weak, immune)\n",
" \n",
" @property\n",
" def ep(self):\n",
" return self.units * self.ap\n",
" \n",
" @property\n",
" def dead(self):\n",
" return self.units <= 0\n",
" \n",
" def calc_damage(self, target):\n",
" if self.at in target.immune: return 0\n",
" mul = 2 if self.at in target.weak else 1\n",
" return self.ep * mul\n",
" \n",
" def attack(self, target):\n",
" damage = self.calc_damage(target) // target.hp\n",
" target.units -= damage\n",
" return damage"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"22996"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def solve1():\n",
" immune, infect = [[Group.parse(i, group) for group in army.splitlines()[1:]] for i, army in enumerate(puzzle.split(\"\\n\\n\"))]\n",
" \n",
" while immune and infect:\n",
" targets = {}\n",
" imm_att = set(immune)\n",
" inf_att = set(infect)\n",
" \n",
" for group in sorted(immune + infect, key=lambda g: (-g.ep, -g.init)):\n",
" attackable = [inf_att, imm_att][group.army]\n",
" if not attackable: continue\n",
" target = max(attackable, key=lambda g: (group.calc_damage(g), g.ep, g.init))\n",
" if not group.calc_damage(target): continue\n",
" attackable.remove(target)\n",
" targets[group] = target\n",
" \n",
" for group, target in sorted(targets.items(), key=lambda a: -a[0].init):\n",
" if group.dead: continue\n",
" group.attack(target)\n",
" \n",
" immune, infect = [[g for g in x if not g.dead] for x in [immune, infect]]\n",
" \n",
" return sum(g.units for g in immune + infect)\n",
"\n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"49.2 ms ± 15.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 2"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4327"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def test(boost):\n",
" immune, infect = [[Group.parse(i, group, boost if i == 0 else 0) for group in army.splitlines()[1:]] for i, army in enumerate(puzzle.split(\"\\n\\n\"))]\n",
" \n",
" while immune and infect:\n",
" targets = {}\n",
" imm_att = set(immune)\n",
" inf_att = set(infect)\n",
" \n",
" for group in sorted(immune + infect, key=lambda g: (-g.ep, -g.init)):\n",
" attackable = [inf_att, imm_att][group.army]\n",
" if not attackable: continue\n",
" target = max(attackable, key=lambda g: (group.calc_damage(g), g.ep, g.init))\n",
" if not group.calc_damage(target): continue\n",
" attackable.remove(target)\n",
" targets[group] = target\n",
" \n",
" ok = False\n",
" for group, target in sorted(targets.items(), key=lambda a: -a[0].init):\n",
" if group.dead: continue\n",
" if group.attack(target): ok = True\n",
" \n",
" if not ok:\n",
" break\n",
" \n",
" immune, infect = [[g for g in x if not g.dead] for x in [immune, infect]]\n",
" \n",
" if infect: return None\n",
" return sum(g.units for g in immune)\n",
"\n",
"def solve2():\n",
" boost = 0\n",
" while not (out := test(boost)): boost += 1\n",
" return out\n",
"\n",
"solve2()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3.63 s ± 289 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve2()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

128
Python/2018/24.py Normal file
View file

@ -0,0 +1,128 @@
from lib import *
input = read_input(2018, 24)
@dataclass
class Group:
army: int
units: int
hp: int
ap: int
at: str
init: int
weak: set[str]
immune: set[str]
def __hash__(self):
return id(self)
@staticmethod
def parse(army, line, boost=0):
units, hp, _, extra, ap, at, init = re.match(
r"^(\d+) units each with (\d+) hit points( \((.*)\))? with an attack that does (\d+) (\w+) damage at initiative (\d+)$",
line,
).groups()
weak = set()
immune = set()
for part in extra.split("; ") if extra else []:
t, _, *xs = part.split()
{"weak": weak, "immune": immune}[t].update(x.strip(",") for x in xs)
return Group(army, int(units), int(hp), int(ap) + boost, at, int(init), weak, immune)
@property
def ep(self):
return self.units * self.ap
@property
def dead(self):
return self.units <= 0
def calc_damage(self, target):
if self.at in target.immune:
return 0
mul = 2 if self.at in target.weak else 1
return self.ep * mul
def attack(self, target):
damage = self.calc_damage(target) // target.hp
target.units -= damage
return damage
immune, infect = [
[Group.parse(i, group) for group in army.splitlines()[1:]] for i, army in enumerate(input.split("\n\n"))
]
while immune and infect:
targets = {}
imm_att = set(immune)
inf_att = set(infect)
for group in sorted(immune + infect, key=lambda g: (-g.ep, -g.init)):
attackable = [inf_att, imm_att][group.army]
if not attackable:
continue
target = max(attackable, key=lambda g: (group.calc_damage(g), g.ep, g.init))
if not group.calc_damage(target):
continue
attackable.remove(target)
targets[group] = target
for group, target in sorted(targets.items(), key=lambda a: -a[0].init):
if group.dead:
continue
group.attack(target)
immune, infect = [[g for g in x if not g.dead] for x in [immune, infect]]
print(sum(g.units for g in immune + infect))
def test(boost):
immune, infect = [
[Group.parse(i, group, boost if i == 0 else 0) for group in army.splitlines()[1:]]
for i, army in enumerate(input.split("\n\n"))
]
while immune and infect:
targets = {}
imm_att = set(immune)
inf_att = set(infect)
for group in sorted(immune + infect, key=lambda g: (-g.ep, -g.init)):
attackable = [inf_att, imm_att][group.army]
if not attackable:
continue
target = max(attackable, key=lambda g: (group.calc_damage(g), g.ep, g.init))
if not group.calc_damage(target):
continue
attackable.remove(target)
targets[group] = target
ok = False
for group, target in sorted(targets.items(), key=lambda a: -a[0].init):
if group.dead:
continue
if group.attack(target):
ok = True
if not ok:
break
immune, infect = [[g for g in x if not g.dead] for x in [immune, infect]]
if infect:
return None
return sum(g.units for g in immune)
boost = 0
while not (out := test(boost)):
boost += 1
print(out)

View file

@ -1,121 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"# Day 25"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys; sys.path.insert(0, \"..\")\n",
"\n",
"import aoc\n",
"\n",
"year, day = 2018, 25\n",
"\n",
"puzzle = aoc.setup(year, day)\n",
"plines = puzzle.splitlines()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Puzzle 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"394"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"class UnionFind:\n",
" def __init__(self, n):\n",
" self.parents = list(range(n))\n",
" \n",
" def find(self, x):\n",
" if self.parents[x] == x: return x\n",
" self.parents[x] = self.find(self.parents[x])\n",
" return self.parents[x]\n",
" \n",
" def merge(self, x, y):\n",
" x = self.find(x)\n",
" y = self.find(y)\n",
" self.parents[x] = y\n",
"\n",
"def solve1():\n",
" coords = [tuple(map(int, line.split(\",\"))) for line in plines]\n",
" uf = UnionFind(len(coords))\n",
" for i in range(len(coords)):\n",
" for j in range(i+1, len(coords)):\n",
" if sum(abs(a-b) for a, b in zip(coords[i], coords[j])) <= 3:\n",
" uf.merge(i, j)\n",
" return len(set(map(uf.find, range(len(coords)))))\n",
" \n",
"solve1()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.37 s ± 129 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit solve1()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

13
Python/2018/25.py Normal file
View file

@ -0,0 +1,13 @@
from lib import *
input = read_input(2018, 25)
coords = [tuple(map(int, line.split(","))) for line in input.splitlines()]
uf = UnionFind(len(coords))
for i in range(len(coords)):
for j in range(i + 1, len(coords)):
if sum(abs(a - b) for a, b in zip(coords[i], coords[j])) <= 3:
uf.merge(i, j)
print(len(set(map(uf.find, range(len(coords))))))

View file

@ -20,15 +20,17 @@ import math
import operator
import re
import statistics
from collections import Counter
from collections import Counter, deque
from copy import deepcopy
from dataclasses import dataclass
from datetime import date, datetime, time, timedelta
from functools import cache, partial, reduce
from heapq import heapify, heappop, heappush
from pathlib import Path
import numpy as np
import pyperclip
import z3
def read_input(year: int, day: int) -> str:

View file

@ -41,11 +41,11 @@
## [2018](https://adventofcode.com/2018) ([<img height=18 src=".assets/py.svg"> Python](Python/2018): 25/25)
|Mo|Tu|We|Th|Fr|Sa|Su|
|-|-|-|-|-|-|-|
||||||[**1**](https://adventofcode.com/2018/day/1) [<img height=12 src=".assets/py.svg">](Python/2018/01 "Python solution for 2018/01")|[**2**](https://adventofcode.com/2018/day/2) [<img height=12 src=".assets/py.svg">](Python/2018/02 "Python solution for 2018/02")|
|[**3**](https://adventofcode.com/2018/day/3) [<img height=12 src=".assets/py.svg">](Python/2018/03 "Python solution for 2018/03")|[**4**](https://adventofcode.com/2018/day/4) [<img height=12 src=".assets/py.svg">](Python/2018/04 "Python solution for 2018/04")|[**5**](https://adventofcode.com/2018/day/5) [<img height=12 src=".assets/py.svg">](Python/2018/05 "Python solution for 2018/05")|[**6**](https://adventofcode.com/2018/day/6) [<img height=12 src=".assets/py.svg">](Python/2018/06 "Python solution for 2018/06")|[**7**](https://adventofcode.com/2018/day/7) [<img height=12 src=".assets/py.svg">](Python/2018/07 "Python solution for 2018/07")|[**8**](https://adventofcode.com/2018/day/8) [<img height=12 src=".assets/py.svg">](Python/2018/08 "Python solution for 2018/08")|[**9**](https://adventofcode.com/2018/day/9) [<img height=12 src=".assets/py.svg">](Python/2018/09 "Python solution for 2018/09")|
|[**10**](https://adventofcode.com/2018/day/10) [<img height=12 src=".assets/py.svg">](Python/2018/10 "Python solution for 2018/10")|[**11**](https://adventofcode.com/2018/day/11) [<img height=12 src=".assets/py.svg">](Python/2018/11.ipynb "Python solution for 2018/11")|[**12**](https://adventofcode.com/2018/day/12) [<img height=12 src=".assets/py.svg">](Python/2018/12.ipynb "Python solution for 2018/12")|[**13**](https://adventofcode.com/2018/day/13) [<img height=12 src=".assets/py.svg">](Python/2018/13.ipynb "Python solution for 2018/13")|[**14**](https://adventofcode.com/2018/day/14) [<img height=12 src=".assets/py.svg">](Python/2018/14.ipynb "Python solution for 2018/14")|[**15**](https://adventofcode.com/2018/day/15) [<img height=12 src=".assets/py.svg">](Python/2018/15.ipynb "Python solution for 2018/15")|[**16**](https://adventofcode.com/2018/day/16) [<img height=12 src=".assets/py.svg">](Python/2018/16.ipynb "Python solution for 2018/16")|
|[**17**](https://adventofcode.com/2018/day/17) [<img height=12 src=".assets/py.svg">](Python/2018/17.ipynb "Python solution for 2018/17")|[**18**](https://adventofcode.com/2018/day/18) [<img height=12 src=".assets/py.svg">](Python/2018/18.ipynb "Python solution for 2018/18")|[**19**](https://adventofcode.com/2018/day/19) [<img height=12 src=".assets/py.svg">](Python/2018/19.ipynb "Python solution for 2018/19")|[**20**](https://adventofcode.com/2018/day/20) [<img height=12 src=".assets/py.svg">](Python/2018/20.ipynb "Python solution for 2018/20")|[**21**](https://adventofcode.com/2018/day/21) [<img height=12 src=".assets/py.svg">](Python/2018/21.ipynb "Python solution for 2018/21")|[**22**](https://adventofcode.com/2018/day/22) [<img height=12 src=".assets/py.svg">](Python/2018/22.ipynb "Python solution for 2018/22")|[**23**](https://adventofcode.com/2018/day/23) [<img height=12 src=".assets/py.svg">](Python/2018/23.ipynb "Python solution for 2018/23")|
|[**24**](https://adventofcode.com/2018/day/24) [<img height=12 src=".assets/py.svg">](Python/2018/24.ipynb "Python solution for 2018/24")|[**25**](https://adventofcode.com/2018/day/25) [<img height=12 src=".assets/py.svg">](Python/2018/25.ipynb "Python solution for 2018/25")|26|27|28|29|30|
||||||[**1**](https://adventofcode.com/2018/day/1) [<img height=12 src=".assets/py.svg">](Python/2018/01.py "Python solution for 2018/01")|[**2**](https://adventofcode.com/2018/day/2) [<img height=12 src=".assets/py.svg">](Python/2018/02.py "Python solution for 2018/02")|
|[**3**](https://adventofcode.com/2018/day/3) [<img height=12 src=".assets/py.svg">](Python/2018/03.py "Python solution for 2018/03")|[**4**](https://adventofcode.com/2018/day/4) [<img height=12 src=".assets/py.svg">](Python/2018/04.py "Python solution for 2018/04")|[**5**](https://adventofcode.com/2018/day/5) [<img height=12 src=".assets/py.svg">](Python/2018/05.py "Python solution for 2018/05")|[**6**](https://adventofcode.com/2018/day/6) [<img height=12 src=".assets/py.svg">](Python/2018/06.py "Python solution for 2018/06")|[**7**](https://adventofcode.com/2018/day/7) [<img height=12 src=".assets/py.svg">](Python/2018/07.py "Python solution for 2018/07")|[**8**](https://adventofcode.com/2018/day/8) [<img height=12 src=".assets/py.svg">](Python/2018/08.py "Python solution for 2018/08")|[**9**](https://adventofcode.com/2018/day/9) [<img height=12 src=".assets/py.svg">](Python/2018/09.py "Python solution for 2018/09")|
|[**10**](https://adventofcode.com/2018/day/10) [<img height=12 src=".assets/py.svg">](Python/2018/10.py "Python solution for 2018/10")|[**11**](https://adventofcode.com/2018/day/11) [<img height=12 src=".assets/py.svg">](Python/2018/11.py "Python solution for 2018/11")|[**12**](https://adventofcode.com/2018/day/12) [<img height=12 src=".assets/py.svg">](Python/2018/12.py "Python solution for 2018/12")|[**13**](https://adventofcode.com/2018/day/13) [<img height=12 src=".assets/py.svg">](Python/2018/13.py "Python solution for 2018/13")|[**14**](https://adventofcode.com/2018/day/14) [<img height=12 src=".assets/py.svg">](Python/2018/14.py "Python solution for 2018/14")|[**15**](https://adventofcode.com/2018/day/15) [<img height=12 src=".assets/py.svg">](Python/2018/15.py "Python solution for 2018/15")|[**16**](https://adventofcode.com/2018/day/16) [<img height=12 src=".assets/py.svg">](Python/2018/16.py "Python solution for 2018/16")|
|[**17**](https://adventofcode.com/2018/day/17) [<img height=12 src=".assets/py.svg">](Python/2018/17.py "Python solution for 2018/17")|[**18**](https://adventofcode.com/2018/day/18) [<img height=12 src=".assets/py.svg">](Python/2018/18.py "Python solution for 2018/18")|[**19**](https://adventofcode.com/2018/day/19) [<img height=12 src=".assets/py.svg">](Python/2018/19.py "Python solution for 2018/19")|[**20**](https://adventofcode.com/2018/day/20) [<img height=12 src=".assets/py.svg">](Python/2018/20.py "Python solution for 2018/20")|[**21**](https://adventofcode.com/2018/day/21) [<img height=12 src=".assets/py.svg">](Python/2018/21.py "Python solution for 2018/21")|[**22**](https://adventofcode.com/2018/day/22) [<img height=12 src=".assets/py.svg">](Python/2018/22.py "Python solution for 2018/22")|[**23**](https://adventofcode.com/2018/day/23) [<img height=12 src=".assets/py.svg">](Python/2018/23.py "Python solution for 2018/23")|
|[**24**](https://adventofcode.com/2018/day/24) [<img height=12 src=".assets/py.svg">](Python/2018/24.py "Python solution for 2018/24")|[**25**](https://adventofcode.com/2018/day/25) [<img height=12 src=".assets/py.svg">](Python/2018/25.py "Python solution for 2018/25")|26|27|28|29|30|
|31|||||||
## [2017](https://adventofcode.com/2017) ([<img height=18 src=".assets/py.svg"> Python](Python/2017): 25/25)

View file

@ -54,6 +54,7 @@
# Python
(python311.withPackages (p:
with p; [
z3
numpy
pyperclip
]))

View file

@ -3,7 +3,7 @@ from datetime import date
from pathlib import Path
names = {"rs": "Rust", "hs": "Haskell", "py": "Python", "apl": "APL"}
exts = {"rs": [".rs"], "hs": [".hs"], "py": [".py", ".ipynb", ""], "apl": [".apl"]}
exts = {"rs": [".rs"], "hs": [".hs"], "py": [".py", ""], "apl": [".apl"]}
def logo(lang, height=12):