| .DS_Store | .DS_Store | ||||
| venv/ | venv/ | ||||
| .env | .env | ||||
| *.js |
| include .env | include .env | ||||
| FILE = $(shell find . -path "./y????/p??.py" -type f | xargs ls -rt | tail -n 1) | FILE = $(shell find . -path "./y????/p??.py" -type f | xargs ls -rt | tail -n 1) | ||||
| DATA = $(shell echo $(FILE) | sed -e s/\.py/\.dat/) | |||||
| PYTHONPATH = . | PYTHONPATH = . | ||||
| export | export | ||||
| main: venv/ $(DATA) | main: venv/ $(DATA) | ||||
| @cat $(DATA) | venv/bin/python -u $(FILE) | |||||
| venv/bin/python -u toolkit.py $(FILE) | |||||
| flake: venv/ | flake: venv/ | ||||
| venv/bin/flake8 --exclude=venv/ | venv/bin/flake8 --exclude=venv/ | ||||
| $(DATA): | |||||
| @echo $(DATA) | venv/bin/python -c "import toolkit; toolkit.get_dat()" $(DATA) | |||||
| venv/: requirements.txt | venv/: requirements.txt | ||||
| rm -rf venv/ | rm -rf venv/ | ||||
| ~/.pyenv/versions/3.8.0/bin/python -m venv venv | ~/.pyenv/versions/3.8.0/bin/python -m venv venv | ||||
| venv/bin/pip install -r requirements.txt | venv/bin/pip install -r requirements.txt | ||||
| touch requirements.txt venv/ | touch requirements.txt venv/ | ||||
| # install flake8 git hook | # install flake8 git hook | ||||
| echo 'venv/bin/flake8 --exclude=venv/' > .git/hooks/pre-commit | |||||
| chmod +x .git/hooks/pre-commit | |||||
| # echo 'venv/bin/flake8 --exclude=venv/' > .git/hooks/pre-commit | |||||
| # chmod +x .git/hooks/pre-commit |
| import builtins | |||||
| import collections | import collections | ||||
| import hashlib | import hashlib | ||||
| import itertools | import itertools | ||||
| import importlib | |||||
| import math | import math | ||||
| import os | import os | ||||
| import re | import re | ||||
| import string | |||||
| import sys | import sys | ||||
| from pathlib import Path | from pathlib import Path | ||||
| return path[::-1] | return path[::-1] | ||||
| def get_dat(): | |||||
| path = sys.argv[1] | |||||
| year, qn = map(int, re.findall(r'\d+', sys.argv[1])) | |||||
| url = f'https://adventofcode.com/{year}/day/{qn}/input' | |||||
| cookies = {'session': os.environ['SESSION']} | |||||
| response = requests.get(url, cookies=cookies) | |||||
| response.raise_for_status() | |||||
| Path(path).write_bytes(response.content) | |||||
| def ensure_data(path): | |||||
| if not path.exists(): | |||||
| year, qn = map(int, re.findall(r'\d+', sys.argv[1])) | |||||
| url = f'https://adventofcode.com/{year}/day/{qn}/input' | |||||
| cookies = {'session': os.environ['SESSION']} | |||||
| response = requests.get(url, cookies=cookies) | |||||
| response.raise_for_status() | |||||
| path.write_bytes(response.content) | |||||
| def batch(iterable, size): | def batch(iterable, size): | ||||
| count += 1 | count += 1 | ||||
| else: | else: | ||||
| raise RuntimeError('Reached steady state') | raise RuntimeError('Reached steady state') | ||||
| if __name__ == '__main__': | |||||
| data_file = Path(sys.argv[1]).with_suffix('.dat') | |||||
| ensure_data(data_file) | |||||
| builtins.data_file = data_file | |||||
| builtins.string = string | |||||
| builtins.re = re | |||||
| rel = re.sub(r'.+(y\d+)/(p\d+).+', r'\1.\2', os.environ['FILE']) | |||||
| mod = importlib.import_module(rel) | |||||
| print(getattr(mod, 'ans1', None)) | |||||
| print(getattr(mod, 'ans2', None)) |
| import sys | |||||
| ans1 = 0 | ans1 = 0 | ||||
| ans2 = None | ans2 = None | ||||
| for i, char in enumerate(sys.stdin.read(), 1): | |||||
| for i, char in enumerate(data_file.read_text(), 1): | |||||
| ans1 += {'(': 1, ')': -1}[char] | ans1 += {'(': 1, ')': -1}[char] | ||||
| if ans1 == -1 and ans2 is None: | if ans1 == -1 and ans2 is None: | ||||
| ans2 = i | ans2 = i | ||||
| print(ans1) | |||||
| print(ans2) |
| import sys | |||||
| ans1 = 0 | ans1 = 0 | ||||
| ans2 = 0 | ans2 = 0 | ||||
| for line in sys.stdin.readlines(): | |||||
| for line in data_file.read_text().splitlines(): | |||||
| a, b, c = sorted(map(int, line.split('x'))) | a, b, c = sorted(map(int, line.split('x'))) | ||||
| ans1 += 2 * (a * b + b * c + a * c) + a * b | ans1 += 2 * (a * b + b * c + a * c) + a * b | ||||
| ans2 += a * b * c + 2 * (a + b) | ans2 += a * b * c + 2 * (a + b) | ||||
| print(ans1) | |||||
| print(ans2) |
| import sys | |||||
| from itertools import accumulate as acc | from itertools import accumulate as acc | ||||
| text = sys.stdin.read() | |||||
| text = data_file.read_text() | |||||
| dirs = dict(zip('<>^v', [-1, 1, -1j, 1j])) | dirs = dict(zip('<>^v', [-1, 1, -1j, 1j])) | ||||
| ans1 = len({*acc(map(dirs.get, text))}) | ans1 = len({*acc(map(dirs.get, text))}) | ||||
| print(ans1) | |||||
| ans2 = len({*acc(map(dirs.get, text[::2])), *acc(map(dirs.get, text[1::2]))}) | ans2 = len({*acc(map(dirs.get, text[::2])), *acc(map(dirs.get, text[1::2]))}) | ||||
| print(ans2) |
| import sys | |||||
| from hashlib import md5 | from hashlib import md5 | ||||
| from multiprocessing import Pool | from multiprocessing import Pool | ||||
| return i, hasher.hexdigest() | return i, hasher.hexdigest() | ||||
| if __name__ == '__main__': | |||||
| code = sys.stdin.read().strip() | |||||
| ans1 = None | |||||
| ans2 = None | |||||
| with Pool() as pool: | |||||
| for i, coin in pool.starmap(mine, [(code, i) for i in range(10**7)]): | |||||
| if ans1 is None and coin.startswith('00000'): | |||||
| ans1 = i | |||||
| if ans2 is None and coin.startswith('000000'): | |||||
| ans2 = i | |||||
| print(ans1) | |||||
| print(ans2) | |||||
| code = data_file.read_text().strip() | |||||
| ans1 = None | |||||
| ans2 = None | |||||
| for i in range(10**7): | |||||
| i, coin = mine(code, i) | |||||
| if ans1 is None and coin.startswith('00000'): | |||||
| ans1 = i | |||||
| if ans2 is None and coin.startswith('000000'): | |||||
| ans2 = i | |||||
| break |
| import re | |||||
| import sys | |||||
| def checks1(string): | def checks1(string): | ||||
| yield len(re.findall(r'([aeiou])', string)) >= 3 | yield len(re.findall(r'([aeiou])', string)) >= 3 | ||||
| yield len(re.findall(r'(.)\1', string)) | yield len(re.findall(r'(.)\1', string)) | ||||
| ans1 = 0 | ans1 = 0 | ||||
| ans2 = 0 | ans2 = 0 | ||||
| for line in sys.stdin.read().splitlines(): | |||||
| for line in data_file.read_text().splitlines(): | |||||
| ans1 += all(checks1(line)) | ans1 += all(checks1(line)) | ||||
| ans2 += all(checks2(line)) | ans2 += all(checks2(line)) | ||||
| print(ans1) | |||||
| print(ans2) |
| def pythonize(string): | |||||
| op, out = ( | |||||
| re.sub(r'([a-z]+)', r'\1_', string) | |||||
| .replace('AND', '&') | |||||
| .replace('OR', '|') | |||||
| .replace('NOT ', '~') | |||||
| .replace('RSHIFT', '>>') | |||||
| .replace('LSHIFT', '<<') | |||||
| ).split(' -> ') | |||||
| return f'{out} = {op}' | |||||
| def process(instructions, registers={}): | |||||
| while instructions: | |||||
| curr, *instructions = instructions | |||||
| out = curr.split()[0] | |||||
| if out in registers: | |||||
| continue | |||||
| try: | |||||
| exec(curr, None, registers) | |||||
| except NameError: | |||||
| instructions.append(curr) | |||||
| return registers | |||||
| inp = [pythonize(string) for string in data_file.read_text().splitlines()] | |||||
| found = process(inp.copy()) | |||||
| ans1 = found['a_'] | |||||
| ans2 = process(inp.copy(), {'b_': ans1})['a_'] |
| import sys | |||||
| from itertools import permutations | |||||
| text = sys.stdin.read() | |||||
| # transform text into data structures | |||||
| valid = set() | |||||
| target = {} | |||||
| for y, line in enumerate(text.splitlines()): | |||||
| for x, char in enumerate(line): | |||||
| if char == '#': | |||||
| continue | |||||
| valid.add(x + 1j * y) | |||||
| if char != '.': | |||||
| target[x + 1j * y] = char | |||||
| # generate travel map | |||||
| graph = {} | |||||
| for A in target: | |||||
| seen = {A} | |||||
| boundary = {A} | |||||
| pending = set(target) - seen | |||||
| N = 0 | |||||
| while pending: | |||||
| N += 1 | |||||
| boundary = {pos + step for pos in boundary for step in [1, -1, 1j, -1j]} | |||||
| boundary &= valid - seen | |||||
| seen.update(boundary) | |||||
| for B in boundary & pending: | |||||
| pending -= {B} | |||||
| graph[target[A], target[B]] = N | |||||
| # use map to determine routes | |||||
| calc = lambda combo: sum(graph[pair] for pair in zip(combo, combo[1:])) | |||||
| z = '0' | |||||
| rest = set(target.values()) - {z} | |||||
| options = [(z,) + combo for combo in permutations(rest)] | |||||
| ans = min(options, key=calc) | |||||
| print(calc(ans)) | |||||
| options = [(z,) + combo + (z,) for combo in permutations(rest)] | |||||
| ans = min(options, key=calc) | |||||
| print(calc(ans)) |
| inp = data_file.read_text().strip() | |||||
| out = {} | |||||
| for a in [''] + list(string.ascii_lowercase): | |||||
| text = inp.replace(a, '').replace(a.swapcase(), '') | |||||
| stack1 = list(text) | |||||
| stack2 = [] | |||||
| while stack1: | |||||
| x = stack1.pop() | |||||
| if stack2 and x.swapcase() == stack2[-1]: | |||||
| y = stack2.pop() | |||||
| else: | |||||
| stack2.append(x) | |||||
| out[a] = len(stack2) | |||||
| ans1 = out[''] | |||||
| ans2 = min(out.values()) |
| import collections | |||||
| import itertools | |||||
| import re | |||||
| import sys | |||||
| txt = '''90342 ;2 correct | |||||
| 70794 ;0 correct | |||||
| 39458 ;2 correct | |||||
| 34109 ;1 correct | |||||
| 51545 ;2 correct | |||||
| 12531 ;1 correct | |||||
| ''' # 39542 is unique | |||||
| txt = sys.stdin.read() | |||||
| exclusions = collections.defaultdict(set) | |||||
| clues = [] | |||||
| for string, n in re.findall(r'(\d+) ;(\d)', txt): | |||||
| choices = set(enumerate(string)) | |||||
| combos = [frozenset(cs) for cs in itertools.combinations(choices, int(n))] | |||||
| for combo in combos: | |||||
| exclusions[combo] |= (choices - combo) | |||||
| if int(n): | |||||
| clues.append(combos) | |||||
| for pos in range(len(string)): | |||||
| choices = {(pos, char) for char in '0123456789'} | |||||
| for choice in choices: | |||||
| exclusions[frozenset({choice})] |= (choices - {choice}) | |||||
| def solve(clues_left, known=frozenset()): | |||||
| if not clues_left: | |||||
| avail = {a for gr in exclusions for a in gr} | |||||
| avail -= {v for k, vs in exclusions.items() if k <= known for v in vs} | |||||
| yield ''.join(c for _, c in sorted(avail)) | |||||
| else: | |||||
| choices = min(clues_left, key=len) | |||||
| for choice in choices: | |||||
| chosen = known | choice | |||||
| bads = {v for k, vs in exclusions.items() if k <= chosen for v in vs} | |||||
| mods = [[c for c in cl if not c & bads] for cl in clues_left if cl != choices] | |||||
| yield from solve(mods, chosen) | |||||
| solution = next(solve(clues)) | |||||
| print(solution) |