Update 2015 solutions

This commit is contained in:
felixm 2024-10-20 15:19:25 -04:00
parent 87ab42743e
commit e73fa3bae7
16 changed files with 362 additions and 411 deletions

View File

@ -1,8 +1,9 @@
from lib import *
from lib import get_data
data = open(0).read()
data = get_data(__file__)
part_2 = True
t = sum((1 if c == "(" else -1 for c in data))
print(t)
floor = 0
for i, c in enumerate(data):
@ -10,13 +11,6 @@ for i, c in enumerate(data):
floor += 1
elif c == ")":
floor -= 1
else:
print(c)
assert False
if part_2 and floor == -1:
if floor == -1:
print(i + 1)
break
if not part_2:
print(floor)

View File

@ -1,35 +1,29 @@
from functools import lru_cache
data = open(0).read().strip()
from lib import get_data
part_1 = False
if part_1:
repeats = 40
else:
repeats = 50
data = get_data(__file__)
@lru_cache
def look_and_say(data: str) -> str:
r = ""
i = 0
while i < len(data):
count = 0
c = data[i]
while i < len(data) and data[i] == c:
def iter(xs):
if not xs:
return []
grouped = []
current_element = xs[0]
count = 1
for element in xs[1:]:
if element == current_element:
count += 1
i += 1
r += f"{count}{c}"
return r
else:
grouped.append(count)
grouped.append(current_element)
current_element = element
count = 1
grouped.append(count)
grouped.append(current_element)
return grouped
CHUNK_SIZE = 10000
for _ in range(repeats):
ndata = ""
lo, up = 0, CHUNK_SIZE
while up < len(data):
while up < len(data) and data[up - 1] == data[up]:
up += 1
ndata += look_and_say(data[lo:up])
lo, up = up, up + CHUNK_SIZE
ndata += look_and_say(data[lo:up])
data = ndata
print(len(data))
for repeat in [40, 50]:
xs = list(map(int, list(data.strip())))
for _ in range(repeat):
xs = iter(xs)
print(len(xs))

View File

@ -1,4 +1,7 @@
data = open(0).read().strip()
from lib import get_data
data = get_data(__file__).strip()
def is_valid(pw):
# Passwords must include one increasing straight of at least three letters,
@ -26,24 +29,26 @@ def is_valid(pw):
return False
return True
def inc(pw):
pw = list(map(ord, pw))
for i in range(len(pw) - 1, -1, -1):
pw[i] += 1
if pw[i] == ord('z') + 1:
pw[i] = ord('a')
if pw[i] == ord("z") + 1:
pw[i] = ord("a")
else:
break
return "".join(map(chr, pw))
part_1 = False
part_1 = True
valid_count = 0
while True:
data = inc(data)
if is_valid(data):
valid_count += 1
if part_1 and valid_count == 1:
break
elif valid_count == 2:
break
print(data)
elif valid_count == 2:
print(data)
break

View File

@ -1,27 +1,37 @@
from lib import get_data
import json
data = open(0).read().strip()
part_2 = False
data = get_data(__file__).strip()
def addup(d):
r = 0
if isinstance(d, list):
for e in d:
v = addup(e)
if v is not None:
r += v
elif isinstance(d, dict):
for e in d.values():
v = addup(e)
if v is None:
return 0
r += v
elif isinstance(d, str):
if part_2 and d == "red":
return None
o = json.loads(data)
def xsum(obj, part_2=False):
t = 0
if type(obj) is int:
t += obj
elif type(obj) is list:
for o in obj:
t += xsum(o, part_2)
elif type(obj) is dict:
if part_2:
st = 0
for o in obj.values():
st += xsum(o, part_2)
if type(o) is str and o == "red":
break
else:
r += d
return r
t += st
else:
for o in obj.values():
t += xsum(o, part_2)
elif type(obj) is str:
pass
else:
print(obj)
assert False
return t
data = json.loads(data)
print(addup(data))
print(xsum(o))
print(xsum(o, True))

View File

@ -1,35 +1,32 @@
from lib import get_data
from collections import defaultdict
from itertools import permutations
data = open(0).read().strip()
part_2 = False
data = get_data(__file__).strip()
pairs = defaultdict(int)
people = set()
scores = {}
for line in data.splitlines():
a, _, wl, score, _, _, _, _, _, _, b = line.split()
b = b.replace(".", "")
score = int(score)
if wl == "lose":
score = -score
a, _, gainlose, amount, _, _, _, _, _, _, b = line[:-1].split()
amount = int(amount)
if gainlose == "lose":
amount = -amount
pairs[(a, b)] = amount
people.add(a)
people.add(b)
scores[(a, b)] = score
if part_2:
scores[(a, "me")] = 0
scores[("me", a)] = 0
scores[(b, "me")] = 0
scores[("me", b)] = 0
if part_2:
people.add("me")
max_score = 0
for p in permutations(list(people)):
s = 0
for i in range(len(p)):
a, b = p[i], p[(i + 1) % len(p)]
s += scores[(a, b)]
s += scores[(b, a)]
max_score = max(max_score, s)
def calc_gain(people):
maxgain = 0
for xs in permutations(list(people)):
gain = 0
for i in range(len(xs)):
gain += pairs[(xs[i], xs[(i + 1) % len(xs)])]
gain += pairs[(xs[(i + 1) % len(xs)], xs[i])]
maxgain = max(maxgain, gain)
return maxgain
print(max_score)
print(calc_gain(people))
people.add("Felix")
print(calc_gain(people))

View File

@ -1,53 +1,40 @@
import lib
data = open(0).read().strip()
from lib import get_data
from lib import ints, fst
from collections import defaultdict
part_1 = False
rds = []
max_dist = 0
gtime = 2503
rds = []
data = get_data(__file__).strip()
deers = []
for line in data.splitlines():
speed, time, rest = lib.str_to_ints(line)
rds.append([speed, time, rest, 0, 0, 0])
speed *= 1000
speed, time, rest = ints(line)
deers.append([0, speed, time, rest, time, 0])
dist = 0
ctime = 0
while ctime < gtime:
t = min(time, gtime - ctime)
dist += (speed * t)
ctime += time
ctime += rest
max_dist = max(dist, max_dist)
points = defaultdict(int)
for _ in range(2503):
max_dists = defaultdict(list)
for i, deer in enumerate(deers):
dist, speed, time, rest, time_left, rest_left = deer
if time_left > 0:
time_left -= 1
dist += speed
elif time_left == 0:
time_left = -1
rest_left = rest - 1
elif rest_left > 0:
rest_left -= 1
elif rest_left == 0:
time_left = time - 1
dist += speed
rest_left = -1
max_dists[dist].append(i)
if part_1:
print(max_dist // 1000)
deer[0] = dist
deer[4] = time_left
deer[5] = rest_left
scores = [0 for _ in range(len(rds))]
for _ in range(gtime):
for i in range(len(rds)):
speed, time, rest, dist, travel_time, rest_time = rds[i]
rd = rds[i]
if travel_time < time:
rd[3] += speed
rd[4] += 1
elif rest_time < rest:
rd[5] += 1
if rd[5] == rest:
rd[4] = 0
rd[5] = 0
max_deers = max(max_dists.items())
for di in max_deers[1]:
points[di] += 1
max_i = -1
max_v = 0
for i, rd in enumerate(rds):
if rd[3] > max_v:
max_i = i
max_v = rd[3]
for i, rd in enumerate(rds):
if rd[3] == max_v:
scores[i] += 1
if not part_1:
print(max(scores))
print(max(map(fst, deers)))
print(max(points.values()))

View File

@ -1,19 +1,17 @@
from lib import *
from lib import get_data, ints
data = open(0).readlines()
data = get_data(__file__)
part_1 = True
if part_1:
a = 0
for line in data:
l, w, h = list(map(int, line.split("x")))
for line in data.splitlines():
l, w, h = ints(line)
slack = min([l * w, w * h, h * l])
a += (2*l*w + 2*w*h + 2*h*l + slack)
else:
a += 2 * l * w + 2 * w * h + 2 * h * l + slack
print(a)
a = 0
for line in data:
l, w, h = list(map(int, line.split("x")))
for line in data.splitlines():
l, w, h = ints(line)
sd = min([2 * (l + w), 2 * (w + h), 2 * (h + l)])
a += sd + (l * w * h)
print(a)

View File

@ -4,6 +4,7 @@ import lib
data = int(open(0).read().strip())
part_1 = False
def calc(n):
fs = lib.prime_factors(n)
vs = set([1, n])
@ -21,6 +22,7 @@ def calc(n):
r += e * 11
return r
for i in range(3, 10000000):
c = calc(i)
if c >= data:

View File

@ -1,9 +1,7 @@
import sys
from lib import *
from lib import get_data
from lib import V
data = open(0).read()
part_1 = False
data = get_data(__file__)
DIRS = {
"^": (-1, 0),
@ -12,30 +10,27 @@ DIRS = {
"<": (0, -1),
}
if part_1:
pos = (0, 0)
pos = V(0, 0)
poss = set([pos])
for c in data:
d = DIRS[c]
pos = pos[0] + d[0], pos[1] + d[1]
pos = pos + d
poss.add(pos)
print(len(poss))
sys.exit(0)
a = (0, 0)
b = (0, 0)
a = V(0, 0)
b = V(0, 0)
poss = set([a, b])
for i, c in enumerate(data):
if i % 2 == 0:
d = DIRS[c]
a = a[0] + d[0], a[1] + d[1]
a = a + d
poss.add(a)
else:
d = DIRS[c]
b = b[0] + d[0], b[1] + d[1]
b = b + d
poss.add(b)
print(len(poss))
sys.exit(0)

View File

@ -1,15 +1,9 @@
from lib import *
from lib import get_data
import hashlib
part_1 = True
if part_1:
digits = 5
else:
digits = 6
data = open(0).read().strip()
data = get_data(__file__).strip()
for digits in [5, 6]:
for i in range(10**9):
text = data + str(i)
md5_hash = hashlib.md5(text.encode()).hexdigest()
@ -19,4 +13,3 @@ for i in range(10**9):
else:
print(i)
break

View File

@ -1,53 +1,56 @@
from lib import *
from lib import get_data
data = open(0).read()
data = get_data(__file__)
part_1 = True
if part_1:
res = 0
for line in data.splitlines():
def is_nice(line):
# It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
vc = 0
for c in line:
if c in "aoeui":
vc += 1
for v in "aeiou":
vc += line.count(v)
if vc < 3:
continue
return False
prev = None
for c in line:
if c == prev:
break
prev = c
else:
continue
contains = False
ss = ["ab", "cd", "pq", "xy"]
for s in ss:
if s in line:
contains = True
if contains:
continue
res += 1
print(res)
else:
res = 0
for line in data.splitlines():
pairs = {}
for i in range(0, len(line) - 1):
p = line[i:i+2]
if p in pairs and i > pairs[p] + 1:
break
if not p in pairs:
pairs[p] = i
else:
continue
for i in range(0, len(line) - 2):
if line[i] == line[i + 2]:
# It contains at least one letter that appears twice in a row, like xx,
# abcdde (dd), or aabbccdd (aa, bb, cc, or dd).
for i in range(len(line) - 1):
if line[i] == line[i + 1]:
break
else:
continue
res += 1
print(res)
return False
# It does not contain the strings ab, cd, pq, or xy, even if they are
# part of one of the other requirements.
for i in range(len(line) - 1):
cc = "".join(line[i : i + 2])
if cc in ["ab", "cd", "pq", "xy"]:
return False
return True
def is_nice_2(line):
good = False
for i in range(len(line) - 1):
cc = "".join(line[i : i + 2])
for j in range(i + 2, len(line) - 1):
dd = "".join(line[j : j + 2])
if cc == dd:
good = True
if not good:
return False
for i in range(len(line) - 2):
cc = "".join(line[i : i + 3])
if cc[0] == cc[2]:
break
else:
return False
return True
t = sum(1 if is_nice(line) else 0 for line in data.splitlines())
print(t)
t = sum(1 if is_nice_2(line) else 0 for line in data.splitlines())
print(t)

View File

@ -1,33 +1,29 @@
from lib import *
from lib import get_data, ints
from collections import defaultdict as DD
data = open(0).read()
part_2 = True
lights = [[0 for _ in range(1000)] for _ in range(1000)]
data = get_data(__file__)
ons = set()
ons2 = DD(int)
for line in data.splitlines():
x1, y1, x2, y2 = str_to_ints(line)
x1, y1, x2, y2 = ints(line)
for x in range(x1, x2 + 1):
for y in range(y1, y2 + 1):
if part_2:
if "on" in line:
lights[x][y] += 1
elif "off" in line:
lights[x][y] = max(0, lights[x][y] - 1)
if "off" in line:
if (x, y) in ons:
ons.remove((x, y))
ons2[(x, y)] = max(ons2[(x, y)] - 1, 0)
elif "on" in line:
ons.add((x, y))
ons2[(x, y)] += 1
elif "toggle" in line:
if (x, y) in ons:
ons.remove((x, y))
else:
lights[x][y] += 2
ons.add((x, y))
ons2[(x, y)] += 2
else:
if "on" in line:
lights[x][y] = 1
elif "off" in line:
lights[x][y] = 0
else:
if lights[x][y] == 1:
lights[x][y] = 0
else:
lights[x][y] = 1
assert False
res = 0
for row in lights:
res += sum(row)
print(res)
print(len(ons))
print(sum(ons2.values()))

View File

@ -1,90 +1,54 @@
from lib import *
from lib import get_data
data = open(0).read()
data = get_data(__file__)
part_2 = False
if part_2:
gates = {"b": 16076}
def run(wires={}):
def get(a):
try:
return int(a)
except ValueError:
pass
if a in wires:
return wires[a]
else:
gates = {}
return None
while "a" not in gates:
while "a" not in wires:
for line in data.splitlines():
lhs, rhs = line.split(" -> ")
if part_2 and rhs == "b":
if rhs in wires:
continue
lhs = lhs.strip()
if "NOT" in lhs:
op, op1 = lhs.split(" ")
assert op == "NOT"
try:
op1 = int(op1)
gates[rhs] = ~op1 & 0xffff
except ValueError:
if op1 in gates and isinstance(gates[op1], int):
gates[rhs] = ~gates[op1] & 0xffff
elif "OR" in lhs:
op1, op, op2 = lhs.split(" ")
assert op == "OR"
try:
op1 = int(op1)
except ValueError:
if op1 in gates and isinstance(gates[op1], int):
op1 = gates[op1]
try:
op2 = int(op2)
except ValueError:
if op2 in gates and isinstance(gates[op2], int):
op2 = gates[op2]
match lhs.split():
case [a, "AND", b]:
a, b = get(a), get(b)
if a is not None and b is not None:
wires[rhs] = a & b
case [a, "OR", b]:
a, b = get(a), get(b)
if a is not None and b is not None:
wires[rhs] = a | b
case [a, "LSHIFT", b]:
a, b = get(a), get(b)
if a is not None and b is not None:
wires[rhs] = a << b
case [a, "RSHIFT", b]:
a, b = get(a), get(b)
if a is not None and b is not None:
wires[rhs] = a >> b
case ["NOT", a]:
a = get(a)
if a is not None:
wires[rhs] = ~a & 0xFFFF
case [a]:
a = get(a)
if a is not None:
wires[rhs] = a
return wires
if not (isinstance(op1, int) and isinstance(op2, int)):
continue
gates[rhs] = (op1 | op2)
elif "AND" in lhs:
op1, op, op2 = lhs.split(" ")
assert op == "AND"
try:
op1 = int(op1)
except ValueError:
if op1 in gates and isinstance(gates[op1], int):
op1 = gates[op1]
try:
op2 = int(op2)
except ValueError:
if op2 in gates and isinstance(gates[op2], int):
op2 = gates[op2]
if not (isinstance(op1, int) and isinstance(op2, int)):
continue
gates[rhs] = (op1 & op2)
elif "LSHIFT" in lhs:
op1, op, op2 = lhs.split(" ")
op2 = int(op2)
try:
op1 = int(op1)
except ValueError:
if op1 in gates:
op1 = gates[op1]
else:
continue
gates[rhs] = (op1 << op2) & 0xffff
elif "RSHIFT" in lhs:
op1, op, op2 = lhs.split(" ")
op2 = int(op2)
try:
op1 = int(op1)
except ValueError:
if op1 in gates:
op1 = gates[op1]
else:
continue
gates[rhs] = (op1 >> op2) & 0xffff
else:
try:
lhs = int(lhs)
gates[rhs] = lhs
except ValueError:
if lhs in gates:
gates[rhs] = gates[lhs]
a = run()["a"]
print(a)
print(gates["a"])
a2 = run(wires={"b": a})["a"]
print(a2)

View File

@ -1,9 +1,8 @@
from lib import *
from lib import get_data
import re
data = open(0).read()
part_1 = False
data = get_data(__file__)
if part_1:
r1 = re.compile(r"\\x[0-9a-f][0-9a-f]")
r2 = re.compile(r"\\\\")
r3 = re.compile(r"\\\"")
@ -16,11 +15,11 @@ if part_1:
line = r3.sub("^", line)
enc += len(line) - 2
print(mem - enc)
else:
ori, enc = 0, 0
for line in data.splitlines():
ori += len(line)
line = line.replace("\\", "\\\\")
line = line.replace("\"", "\\\"")
line = line.replace('"', '\\"')
enc += len(line) + 2
print(enc - ori)

View File

@ -1,42 +1,27 @@
from lib import *
from typing import Iterator
from lib import get_data
from itertools import permutations
# Just for fun instead of using itertools.permutations.
def permutations(xs) -> Iterator:
assert len(xs) > 0
if len(xs) == 1:
yield xs
else:
x = xs.pop()
for p in permutations(xs):
for i in range(len(p) + 1):
pn = list(p)
pn.insert(i, x)
yield pn
part_1 = False
data = open(0).read()
data = get_data(__file__)
dists = {}
nodes = set()
for line in data.splitlines():
path, dist = line.split(" = ")
dist = int(dist)
a, b = path.split(" to ")
a, _, b, _, d = line.split()
nodes.add(a)
nodes.add(b)
dist = int(d)
dists[(a, b)] = dist
dists[(b, a)] = dist
if part_1:
mdist = 10**12
for route in permutations(nodes):
dist = sum([dists[(route[i], route[i + 1])] for i in range(len(route) - 1)])
mdist = min(dist, mdist)
print(mdist)
else:
mdist = 0
for route in permutations(nodes):
dist = sum([dists[(route[i], route[i + 1])] for i in range(len(route) - 1)])
mdist = max(dist, mdist)
print(mdist)
d_min = 10**12
d_max = 0
for p in permutations(list(nodes)):
d = 0
for i in range(len(p) - 1):
a, b = p[i], p[i + 1]
d += dists[(a, b)]
d_min = min(d, d_min)
d_max = max(d, d_max)
print(d_min)
print(d_max)

33
lib.py
View File

@ -226,7 +226,7 @@ def count_trailing_repeats(lst):
class A_Star(object):
def __init__(self, starts, is_goal, h, d, neighbors):
"""
:param h: heuristic function
:param h: heuristic function (never overestimate)
:param d: cost from node to node function
:param neighbors: neighbors function
"""
@ -297,6 +297,35 @@ def mod_inverse(a, m):
g, x, _ = egcd(a, m)
if g != 1:
raise Exception('Modular inverse does not exist')
raise Exception("Modular inverse does not exist")
else:
return x % m
class V:
def __init__(self, *args):
self.xs: tuple[int] = tuple(args)
def __eq__(self, other):
if isinstance(other, V):
return all(v1 == v2 for v1, v2 in zip(self.xs, other.xs))
elif hasattr(other, "__len__") and len(self.xs) == len(other):
return all(v1 == v2 for v1, v2 in zip(self.xs, other))
return False
def __getitem__(self, i: int):
return self.xs[i]
def __hash__(self):
return hash(self.xs)
def __add__(self, other):
if isinstance(other, V):
return V(*[v1 + v2 for v1, v2 in zip(self.xs, other.xs)])
assert hasattr(other, "__len__"), f"V.__add__({self}, {other}) missing `len`"
assert len(self.xs) == len(other), f"V.__add__({self}, {other}) `len` mismatch"
return V(*[v1 + v2 for v1, v2 in zip(self.xs, other)])
def __repr__(self):
s = ", ".join(map(str, self.xs))
return f"V({s})"