import builtins | import builtins | ||||
import collections | import collections | ||||
import functools | |||||
import hashlib | import hashlib | ||||
import itertools | |||||
import importlib | import importlib | ||||
import itertools | |||||
import math | import math | ||||
import operator | |||||
import os | import os | ||||
import re | import re | ||||
import string | import string | ||||
import requests | 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): | def lcm(a, b): | ||||
data_file = Path(sys.argv[1]).with_suffix('.dat') | data_file = Path(sys.argv[1]).with_suffix('.dat') | ||||
ensure_data(data_file) | ensure_data(data_file) | ||||
builtins.df = data_file | builtins.df = data_file | ||||
builtins.text = data_file.read_text() | |||||
builtins.string = string | builtins.string = string | ||||
builtins.re = re | builtins.re = re | ||||
rel = re.sub(r'.+(y\d+)/(p\d+).+', r'\1.\2', os.environ['FILE']) | rel = re.sub(r'.+(y\d+)/(p\d+).+', r'\1.\2', os.environ['FILE']) |
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') |
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'})) |
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)) |
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) |
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 | |||||
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) |
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) |
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 |
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]) |