| 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]) |