@@ -1,9 +1,11 @@ | |||
import builtins | |||
import collections | |||
import functools | |||
import hashlib | |||
import itertools | |||
import importlib | |||
import itertools | |||
import math | |||
import operator | |||
import os | |||
import re | |||
import string | |||
@@ -13,8 +15,7 @@ from pathlib import Path | |||
import requests | |||
def integers(line): | |||
return [int(n) for n in re.findall(r'\d+', line)] | |||
product = functools.partial(functools.reduce, operator.mul) | |||
def lcm(a, b): | |||
@@ -106,6 +107,7 @@ if __name__ == '__main__': | |||
data_file = Path(sys.argv[1]).with_suffix('.dat') | |||
ensure_data(data_file) | |||
builtins.df = data_file | |||
builtins.text = data_file.read_text() | |||
builtins.string = string | |||
builtins.re = re | |||
rel = re.sub(r'.+(y\d+)/(p\d+).+', r'\1.\2', os.environ['FILE']) |
@@ -0,0 +1,19 @@ | |||
import json | |||
def recurse(data, avoid=None): | |||
type_ = type(data) | |||
if type_ is int: | |||
return data | |||
elif type_ is str: | |||
return 0 | |||
elif type_ is list: | |||
return sum(recurse(el, avoid) for el in data) | |||
elif type_ is dict: | |||
if any(val == avoid for val in data.values()): return 0 | |||
return sum(recurse(value, avoid) for key, value in data.items()) | |||
data = json.loads(df.read_text()) | |||
ans1 = recurse(data) | |||
ans2 = recurse(data, 'red') |
@@ -0,0 +1,20 @@ | |||
import collections | |||
import itertools | |||
happiness = collections.defaultdict(int) | |||
people = set() | |||
for line in df.read_text().splitlines(): | |||
A, verb, N, B = re.findall(r'([A-Z][a-z]+|gain|lose|\d+)', line) | |||
happiness[A, B] = int(N) if verb == 'gain' else -int(N) | |||
people.update({A, B}) | |||
def calc(seq): | |||
return sum(happiness[b, a] + happiness[b, c] | |||
for a, b, c in zip(seq[-1:] + seq[:-1], seq, seq[1:] + seq[:1]) | |||
) | |||
ans1 = max(calc(combo) for combo in itertools.permutations(people)) | |||
ans2 = max(calc(combo) for combo in itertools.permutations(people | {'me'})) |
@@ -0,0 +1,16 @@ | |||
import collections | |||
import itertools | |||
reindeers = [ | |||
itertools.accumulate(itertools.cycle([speed] * act + [0] * rest)) | |||
for line in df.read_text().splitlines() | |||
for speed, act, rest in [map(int, re.findall(r'\d+', line))] | |||
] | |||
traveled = [[next(rr) for _ in range(2503)] for rr in reindeers] | |||
transpose = list(zip(*traveled)) | |||
ans1 = max(transpose[-1]) | |||
points = [[d == max(dsts) for d in dsts] for dsts in transpose] | |||
ans2 = max(sum(pts) for pts in zip(*points)) |
@@ -0,0 +1,19 @@ | |||
from toolkit import product | |||
def combine(qtys): | |||
return [max(0, sum(a * b for a, b in zip(qtys, vs))) for vs in zip(*data)] | |||
data = [ | |||
[int(n) for n in re.findall(r'-?\d+', ln)] | |||
for ln in df.read_text().splitlines() | |||
] | |||
qtys = [ | |||
combine([A, B, C, 100 - A - B - C]) | |||
for A in range(101) | |||
for B in range(101 - A) | |||
for C in range(101 - A - B) | |||
] | |||
ans1 = max(product(combo[:-1]) for combo in qtys) | |||
ans2 = max(product(combo[:-1]) for combo in qtys if combo[-1] == 500) |
@@ -0,0 +1,24 @@ | |||
known = { | |||
'children': 3, | |||
'cats': 7, | |||
'samoyeds': 2, | |||
'pomeranians': 3, | |||
'akitas': 0, | |||
'vizslas': 0, | |||
'goldfish': 5, | |||
'trees': 3, | |||
'cars': 2, | |||
'perfumes': 1, | |||
} | |||
for line in df.read_text().splitlines(): | |||
sue, N, *rest = re.findall(r'\w+', line) | |||
stuff = {k: int(v) for k, v in zip(rest[::2], rest[1::2])} | |||
if all(known[k] == stuff[k] for k in stuff): | |||
ans1 = N | |||
if all( | |||
known[k] < stuff[k] if k in {'cats', 'trees'} | |||
else known[k] > stuff[k] if k in {'pomeranians', 'goldfish'} | |||
else known[k] == stuff[k] | |||
for k in stuff): | |||
ans2 = N | |||
@@ -0,0 +1,14 @@ | |||
def recurse(pending, opts, chain=tuple()): | |||
if pending == 0: | |||
yield chain | |||
else: | |||
for i, opt in enumerate(opts): | |||
yield from recurse(pending - opt, opts[i + 1:], chain + (opt,)) | |||
ns = sorted([int(n) for n in df.read_text().splitlines()], reverse=True) | |||
opts = list(recurse(150, ns)) | |||
ans1 = len(opts) | |||
min_n = min(map(len, opts)) | |||
ans2 = sum(len(opt) == min_n for opt in opts) |
@@ -0,0 +1,24 @@ | |||
def condition(x, y, on): | |||
is_on = (x, y) in on | |||
neighbours_on = sum( | |||
(x + dx, y + dy) in on | |||
for dx in [1, 0, -1] for dy in [1, 0, -1] | |||
if dx or dy | |||
) | |||
return (is_on and neighbours_on in {2, 3}) or neighbours_on == 3 | |||
on1 = { | |||
(x, y) | |||
for y, ln in enumerate(df.read_text().splitlines()) | |||
for x, ch in enumerate(ln) | |||
if ch == '#' | |||
} | |||
on2 = set(on1) | |||
grid = {(x, y) for x in range(100) for y in range(100)} | |||
corners = {(0, 0), (0, 99), (99, 0), (99, 99)} | |||
for _ in range(100): | |||
on1 = {(x, y) for x, y in grid if condition(x, y, on1)} | |||
on2 = {(x, y) for x, y in grid if condition(x, y, on2)} | corners | |||
ans1 = len(on1) | |||
ans2 = len(on2) |
@@ -0,0 +1,19 @@ | |||
pre, seq = text.strip().split('\n\n') | |||
formulas = re.findall(r'(\w+) => (\w+)', pre) | |||
ans1 = len({ | |||
seq[:match.start()] + seq[match.start():].replace(key, val, 1) | |||
for key, val in formulas | |||
for match in re.finditer(key, seq) | |||
}) | |||
ops = formulas | |||
ans2 = 0 | |||
while seq != 'e': | |||
ans2 += 1 | |||
for k, v in ops: | |||
if v in seq: | |||
seq = seq.replace(v, k, 1) | |||
break |
@@ -0,0 +1,50 @@ | |||
import itertools | |||
def is_win(p_hp, p_atk, p_def, b_hp, b_atk, b_def): | |||
while True: | |||
b_hp -= max(1, p_atk - b_def) | |||
if b_hp <= 0: | |||
return True | |||
p_hp -= max(1, b_atk - p_def) | |||
if p_hp <= 0: | |||
return False | |||
weapons = [ | |||
(8, 4, 0), | |||
(10, 5, 0), | |||
(25, 6, 0), | |||
(40, 7, 0), | |||
(74, 8, 0), | |||
] | |||
armors = [ | |||
(0, 0, 0), | |||
(13, 0, 1), | |||
(31, 0, 2), | |||
(53, 0, 3), | |||
(75, 0, 4), | |||
(102, 0, 5), | |||
] | |||
rings = [ | |||
(0, 0, 0), | |||
(0, 0, 0), | |||
(25, 1, 0), | |||
(50, 2, 0), | |||
(100, 3, 0), | |||
(20, 0, 1), | |||
(40, 0, 2), | |||
(80, 0, 3), | |||
] | |||
opts = [ | |||
[sum(vs) for vs in zip(*[w, a, r1, r2])] | |||
for w, a in itertools.product(weapons, armors) | |||
for r1, r2 in itertools.combinations(rings, 2) | |||
] | |||
p_hp = 100 | |||
b_hp, b_atk, b_def = map(int, re.findall(r'(\d+)', text)) | |||
wins = {True: set(), False: set()} | |||
for cost, p_atk, p_def in opts: | |||
wins[is_win(p_hp, p_atk, p_def, b_hp, b_atk, b_def)].add(cost) | |||
ans1 = min(wins[True]) | |||
ans2 = max(wins[False]) |