├── 2015 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── tree.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 16tape.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 19_example.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21-shop.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2016 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── city.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2017 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── circuit.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2018 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── hotchocolate.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2019 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── universe.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2020 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── map.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2021 ├── README.md ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py ├── img │ └── depths.png └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2022 ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 18.py │ ├── 2.py │ ├── 22.py │ ├── 25.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 18.txt │ ├── 2.txt │ ├── 22.txt │ ├── 25.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── 2023 ├── day │ ├── 1.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 2.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── 8.py │ └── 9.py └── input │ ├── 1.txt │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 2.txt │ ├── 3.txt │ ├── 4.txt │ ├── 5.txt │ ├── 6.txt │ ├── 7.txt │ ├── 8.txt │ └── 9.txt ├── .gitignore ├── README.md └── img └── stars.png /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !img/ 3 | !20*/ 4 | !20*/img/ 5 | !20*/day/ 6 | !20*/input/ 7 | !*.md 8 | !*.py 9 | !*.txt 10 | !*.png 11 | -------------------------------------------------------------------------------- /2015/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2015 2 | 3 | ![tree](./img/tree.png) 4 | -------------------------------------------------------------------------------- /2015/day/1.py: -------------------------------------------------------------------------------- 1 | with open('../input/1.txt') as f: 2 | data = [1 if i == '(' else -1 for i in f.read().strip()] 3 | 4 | print sum(data) 5 | print next(i for i in range(len(data)) if sum(data[:i]) == -1) 6 | -------------------------------------------------------------------------------- /2015/day/10.py: -------------------------------------------------------------------------------- 1 | with open('../input/10.txt') as f: 2 | data = map(int, list(f.read().strip())) 3 | 4 | for i in xrange(50): # 40 5 | tmp, cur, cnt = [], data[0], 0 6 | for i in data: 7 | if i != cur: 8 | tmp.extend([cnt, cur]) 9 | cnt, cur = 0, i 10 | cnt += 1 11 | tmp.extend([cnt, cur]) 12 | data = tmp 13 | 14 | print len(data) 15 | -------------------------------------------------------------------------------- /2015/day/11.py: -------------------------------------------------------------------------------- 1 | alphabet = 'abcdefghijklmnopqrstuvwxyz'[::-1] 2 | 3 | with open('../input/11.txt') as f: 4 | passwd = list(f.read()[-2::-1]) 5 | 6 | i, n = 0, 2 7 | while n: 8 | if passwd[i] == 'z': 9 | passwd[i] = 'a' 10 | i += 1 11 | continue 12 | 13 | passwd[i] = chr(ord(passwd[i])+1) 14 | i = 0 15 | 16 | test = ''.join(passwd) 17 | if any(alphabet[i:i+3] in test for i in range(24)) \ 18 | and all(c not in test for c in 'iol') \ 19 | and sum(c*2 in test for c in alphabet) > 1: 20 | n -= 1 21 | print(test[::-1]) 22 | -------------------------------------------------------------------------------- /2015/day/12.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def sum_(data, exclude=None, s=0): 5 | if isinstance(data, int): 6 | return data 7 | 8 | if isinstance(data, dict): 9 | if exclude in data.values(): 10 | return 0 11 | s += sum(sum_(i, exclude) for i in data.values()) 12 | 13 | if isinstance(data, (list, tuple)): 14 | s += sum(sum_(i, exclude) for i in data) 15 | 16 | return s 17 | 18 | 19 | with open('../input/12.txt') as f: 20 | data = json.load(f) 21 | 22 | print(sum_(data)) 23 | print(sum_(data, exclude='red')) 24 | -------------------------------------------------------------------------------- /2015/day/13.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | def seat(name, names, n): 5 | if not names: 6 | return n + data[frozenset([name, starting_name])] 7 | 8 | return max(seat(name_, names - {name_}, n + data[frozenset([name, name_])]) 9 | for name_ in names) 10 | 11 | 12 | data = defaultdict(int) 13 | with open('../input/13.txt') as f: 14 | for name, _, gain, n, *_, name_ in map(str.split, f.readlines()): 15 | data[frozenset([name, name_[:-1]])] += int(n) * (-1)**(gain != 'gain') 16 | 17 | names = {name for name_pair in data for name in name_pair} 18 | # names = names.union({'me'}) 19 | 20 | starting_name = names.pop() 21 | print(seat(starting_name, names, 0)) 22 | -------------------------------------------------------------------------------- /2015/day/14.py: -------------------------------------------------------------------------------- 1 | with open('../input/14.txt') as f: 2 | reindeers = [[int(word) for word in line.split() if word.isdigit()] 3 | for line in f] 4 | 5 | time = 2503 6 | print(max((time // (fly + rest)*fly + min(time % (fly + rest), fly)) * speed 7 | for speed, fly, rest in reindeers)) 8 | 9 | points = [0]*len(reindeers) 10 | distance = [0]*len(reindeers) 11 | flying = [fly-1 for _, fly, _ in reindeers] 12 | for _ in range(time): 13 | for reindeer, (speed, fly, rest) in enumerate(reindeers): 14 | if flying[reindeer] >= 0: 15 | distance[reindeer] += speed 16 | 17 | elif flying[reindeer] <= -rest: 18 | flying[reindeer] = fly 19 | 20 | flying[reindeer] -= 1 21 | 22 | max_distance = max(distance) 23 | for reindeer in range(len(distance)): 24 | if distance[reindeer] == max_distance: 25 | points[reindeer] += 1 26 | 27 | print(max(points)) 28 | -------------------------------------------------------------------------------- /2015/day/15.py: -------------------------------------------------------------------------------- 1 | import re 2 | from math import prod 3 | 4 | with open('../input/15.txt') as f: 5 | data = [list(map(int, re.findall(r'-?\d+', line))) for line in f] 6 | 7 | max_score, best_cookie_score = 0, 0 8 | for i in range(101): 9 | for j in range(101-i): 10 | for k in range(101-i-j): 11 | l = 100-i-j-k 12 | score = prod(max(0, sum(y*z for y,z in zip(x, (i,j,k,l)))) 13 | for x in list(zip(*data))[:-1]) 14 | 15 | calories = sum(x[-1]*y for x, y in zip(data, (i,j,k,l))) 16 | max_score = max(max_score, score) 17 | if calories == 500: 18 | best_cookie_score = max(best_cookie_score, score) 19 | 20 | print(max_score) 21 | print(best_cookie_score) 22 | -------------------------------------------------------------------------------- /2015/day/16.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open('../input/16.txt') as f, open('../input/16tape.txt') as ftt: 4 | data = [{x[:3]: int(y) for x, y in re.findall(r'(\w+): (\d+)', line)} 5 | for line in f] 6 | tape = {x[:3]: int(y) for x, y in map(lambda l: l.split(': '), ftt)} 7 | 8 | print(next(aunt+1 for aunt, test in enumerate(data) 9 | if all(tape[i] == test[i] for i in test))) 10 | 11 | print(next(aunt+1 for aunt, test in enumerate(data) 12 | if all(i not in {'cat', 'tre', 'pom', 'gol'} and tape[i] == test[i] 13 | or i in {'cat', 'tre'} and tape[i] < test[i] 14 | or i in {'pom', 'gol'} and tape[i] > test[i] 15 | for i in test))) 16 | -------------------------------------------------------------------------------- /2015/day/17.py: -------------------------------------------------------------------------------- 1 | def num(l, m, d): 2 | if m == 0: 3 | k.append(d) 4 | return 1 5 | s = 0 6 | for i in range(len(l)): 7 | s += num(l[i + 1:], m - l[i], d + 1) 8 | return s 9 | 10 | with open('../input/17.txt') as f: 11 | data = [int(i) for i in f.readlines()] 12 | 13 | k = [] 14 | print num(data, 150, 1) 15 | print k.count(min(k)) 16 | -------------------------------------------------------------------------------- /2015/day/18.py: -------------------------------------------------------------------------------- 1 | def getn(data): 2 | return sum(data[x][y] for x in xrange(i - 1, i + 2) for y in xrange(j - 1, j + 2) \ 3 | if (x != i or y != j) and x >= 0 and y >= 0 and x < 100 and y < 100) 4 | 5 | def setc(data): 6 | for i in [0, 99]: 7 | for j in [0, 99]: 8 | data[i][j] = 1 9 | return data 10 | 11 | with open('../input/18.txt') as fp: 12 | data = [map(int, list(i[:-1].replace('#', '1').replace('.', '0'))) for i in fp.readlines()] 13 | 14 | data = setc(data) 15 | for z in xrange(100): 16 | tmp = [[0 for y in xrange(100)] for x in xrange(100)] 17 | for i in xrange(100): 18 | for j in xrange(100): 19 | n = getn(data) 20 | tmp[i][j] = 0 if data[i][j] == 1 and n not in [2, 3] else data[i][j] 21 | tmp[i][j] = 1 if data[i][j] == 0 and n == 3 else tmp[i][j] 22 | # data = tmp 23 | data = setc(tmp) 24 | 25 | print sum(j for i in data for j in i) 26 | -------------------------------------------------------------------------------- /2015/day/19.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def swap(s, sub, repl): 4 | find = s.find(sub) 5 | while find != -1: 6 | yield s[:find] + repl + s[find + len(sub):] 7 | find = s.find(sub, find + 1) 8 | 9 | with open('../input/19.txt') as fp: 10 | tmp = [i.split(' => ') for i in fp.read().splitlines() if i != ''] 11 | molecule = tmp.pop()[0] 12 | replacements = {y: i for x, y in tmp for i, j in tmp if j == y} 13 | 14 | print(len(set([j for i in replacements for j in swap(molecule, replacements[i], i)]))) 15 | 16 | for i in xrange(10): # increase if needed 17 | cnt, mole = 0, molecule 18 | for z in xrange(10000): 19 | i = random.choice(list(replacements)) 20 | find = mole.find(i) 21 | if find != -1: 22 | cnt += 1 23 | mole = mole[:find] + replacements[i] + mole[find + len(i):] 24 | if mole == 'e': 25 | print(cnt) 26 | break 27 | -------------------------------------------------------------------------------- /2015/day/2.py: -------------------------------------------------------------------------------- 1 | with open("../input/2.txt") as f: 2 | edges = [list(map(int, line.split('x'))) for line in f.readlines()] 3 | 4 | print(sum(2 * (x*y + y*z + z*x) + min(x*y, y*z, z*x) for x, y, z in edges)) 5 | print(sum(2 * sum(sorted([x, y, z])[:2]) + x*y*z for x, y, z in edges)) 6 | -------------------------------------------------------------------------------- /2015/day/20.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | with open('../input/20.txt') as f: 4 | data = int(f.read().strip()) 5 | 6 | for i in xrange(51, 2636363, 1): 7 | # if sum(filter(lambda x: i % x == 0, xrange(1, i + 1))) * 10 >= data: 8 | if sum(filter(lambda x: i % x == 0, xrange(i / 50, i + 1))) * 11 >= data: 9 | print i 10 | break 11 | -------------------------------------------------------------------------------- /2015/day/21.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def score(l): 4 | myHp, myAtt, myDef = [sum(i) for i in zip(*l)] 5 | myHp = 100 6 | return True if ceil(bHp / (myAtt - bDef if myAtt - bDef > 0 else 1)) <= \ 7 | ceil(myHp / (bAtt - myDef if bAtt - myDef > 0 else 1)) else False 8 | 9 | with open('../input/21.txt') as fp, open('../input/21-shop.txt') as fs: 10 | shop = [[map(int, j.split()[1:]) for j in i.splitlines()[1:]] for i in fs.read().strip().split("\n\n")] 11 | bHp, bAtt, bDef = [int(i.split(': ')[1]) for i in fp.readlines()] 12 | 13 | shop[1].append((0, 0, 0)) 14 | shop[2].extend([(0, 0, 0), (0, 0, 0)]) 15 | print min(sum(i[0] for i in [w, a, r1, r2]) for w in shop[0] for a in shop[1] for r1 in shop[2] for r2 in shop[2] if score([w, a, r1, r2]) and r1 != r2) 16 | print max(sum(i[0] for i in [w, a, r1, r2]) for w in shop[0] for a in shop[1] for r1 in shop[2] for r2 in shop[2] if not score([w, a, r1, r2]) and r1 != r2) 17 | -------------------------------------------------------------------------------- /2015/day/23.py: -------------------------------------------------------------------------------- 1 | f = { 2 | 'hlf': lambda r, pc, x: (r / 2, pc + 1), 3 | 'tpl': lambda r, pc, x: (r * 3, pc + 1), 4 | 'inc': lambda r, pc, x: (r + 1, pc + 1), 5 | 'jmp': lambda r, pc, x: (r, pc + int(x)), 6 | 'jie': lambda r, pc, x: (r, pc + int(x) if r % 2 == 0 else pc + 1), 7 | 'jio': lambda r, pc, x: (r, pc + int(x) if r == 1 else pc + 1) 8 | } 9 | 10 | with open('../input/23.txt') as fp: 11 | instructions = [i.split() for i in fp.read().strip().replace('+', '').replace(',', '').splitlines()] 12 | 13 | # pc, r = 0, {'a': 0, 'b': 0} 14 | pc, r = 0, {'a': 1, 'b': 0} 15 | while True: 16 | if pc >= len(instructions): 17 | print r['b'] 18 | break 19 | cur = instructions[pc] 20 | register = cur[1] if cur[1] in r else 'a' 21 | r[register], pc = f[cur[0]](r[register], pc, cur[-1]) 22 | -------------------------------------------------------------------------------- /2015/day/24.py: -------------------------------------------------------------------------------- 1 | from operator import mul 2 | from itertools import combinations 3 | 4 | with open('../input/24.txt') as f: 5 | data = map(int, f.readlines()) 6 | 7 | print min(set(reduce(mul, i) for i in combinations(data, 6) if sum(i) == sum(data) / 3)) 8 | print min(set(reduce(mul, i) for i in combinations(data, 4) if sum(i) == sum(data) / 4)) 9 | -------------------------------------------------------------------------------- /2015/day/25.py: -------------------------------------------------------------------------------- 1 | with open('../input/25.txt') as f: 2 | row, column = [int(n[:-1]) for n in f.read().split() if n[0].isdigit()] 3 | 4 | code = (column + row - 1) * (column + row) // 2 - row 5 | print(20151125 * pow(252533, code, 33554393) % 33554393) 6 | -------------------------------------------------------------------------------- /2015/day/3.py: -------------------------------------------------------------------------------- 1 | f = { 2 | "^": lambda xy: (xy[0] - 1, xy[1]), 3 | "v": lambda xy: (xy[0] + 1, xy[1]), 4 | "<": lambda xy: (xy[0], xy[1] - 1), 5 | ">": lambda xy: (xy[0], xy[1] + 1) 6 | } 7 | 8 | with open('../input/3.txt') as fp: 9 | data = fp.read().strip() 10 | 11 | grid, xy = {(0, 0): 1}, [[0, 0], [0, 0]] 12 | for i in xrange(len(data)): 13 | # mod = 0 14 | mod = i % 2 15 | xy[mod] = f[data[i]](xy[mod]) 16 | if xy[mod] not in grid: 17 | grid[xy[mod]] = 0 18 | grid[xy[mod]] += 1 19 | 20 | print len(grid) 21 | -------------------------------------------------------------------------------- /2015/day/4.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import itertools 3 | 4 | with open("../input/4.txt") as f: 5 | data = f.read().strip() 6 | 7 | for i in itertools.count(): 8 | hex = hashlib.md5((data + str(i)).encode()).hexdigest() 9 | if hex.startswith('000000'): # '00000' 10 | print(i) 11 | break 12 | -------------------------------------------------------------------------------- /2015/day/5.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open('../input/5.txt') as f: 4 | data = f.readlines() 5 | 6 | rules = r'([aeiou].*){3}', r'(.)\1', r'^((?!ab|cd|pq|xy).)*$' 7 | # rules = r'(..).*\1', r'(.).\1' 8 | print(sum(all(re.search(pattern, i) for pattern in rules) for i in data)) 9 | -------------------------------------------------------------------------------- /2015/day/6.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | with open('../input/6.txt') as f: 4 | data = [line.replace(',', ' ').split() for line in f.readlines()] 5 | 6 | grid = np.zeros((1000, 1000)) 7 | for *cmd, x, y, _, z, w in data: 8 | x, y, z, w = map(int, [x, y, z, w]) 9 | if cmd[0] == 'toggle': 10 | grid[x:z+1, y:w+1] = 1 - grid[x:z+1, y:w+1] 11 | # grid[x:z+1, y:w+1] += 2 12 | 13 | elif cmd[1] == 'on': 14 | grid[x:z+1, y:w+1] = 1 # = -> += 15 | 16 | elif cmd[1] == 'off': 17 | grid[x:z+1, y:w+1] = -1 # = -> += 18 | 19 | grid[grid < 0] = 0 20 | 21 | print(int(np.sum(grid))) 22 | -------------------------------------------------------------------------------- /2015/day/7.py: -------------------------------------------------------------------------------- 1 | def get(x): 2 | if type(x) == int or x.isdigit(): 3 | power[x] = int(x) 4 | elif x not in power: 5 | function, a, b, = data[x] 6 | power[x] = function(a, b) 7 | return power[x] 8 | 9 | def o(ins): 10 | if 'NOT' in ins: return lambda a, b: ~ get(b) 11 | if 'AND' in ins: return lambda a, b: get(a) & get(b) 12 | if 'OR' in ins: return lambda a, b: get(a) | get(b) 13 | if 'RSHIFT' in ins: return lambda a, b: get(a) >> get(b) 14 | if 'LSHIFT' in ins: return lambda a, b: get(a) << get(b) 15 | else: return lambda a, b: get(a) 16 | 17 | with open('../input/7.txt') as f: 18 | data = {x: (o(i), i[0], i[-1]) for *i, _, x in map(str.split, f)} 19 | 20 | power = {} 21 | print(a := get('a')) 22 | power = {'b': a} 23 | print(get('a')) 24 | -------------------------------------------------------------------------------- /2015/day/8.py: -------------------------------------------------------------------------------- 1 | with open('../input/8.txt') as f: 2 | data = f.read().strip().splitlines() 3 | 4 | print sum(len(i) - len(i.decode('unicode_escape')) + 2 for i in data) 5 | print sum(len(i.encode('unicode_escape')) + 2 + i.count('\"') - len(i) for i in data) 6 | -------------------------------------------------------------------------------- /2015/day/9.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations, chain 2 | 3 | with open('../input/9.txt') as f: 4 | edges = {frozenset({x, y}): int(z) for x, _, y, _, z in map(str.split, f)} 5 | 6 | cities = set(chain(*edges)) 7 | paths = [sum(edges[frozenset({x, y})] for x, y in zip(p[:-1], p[1:])) 8 | for p in permutations(cities)] 9 | 10 | print(min(paths)) 11 | print(max(paths)) 12 | -------------------------------------------------------------------------------- /2015/img/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2015/img/tree.png -------------------------------------------------------------------------------- /2015/input/10.txt: -------------------------------------------------------------------------------- 1 | 3113322113 2 | -------------------------------------------------------------------------------- /2015/input/11.txt: -------------------------------------------------------------------------------- 1 | hepxcrrq 2 | -------------------------------------------------------------------------------- /2015/input/14.txt: -------------------------------------------------------------------------------- 1 | Rudolph can fly 22 km/s for 8 seconds, but then must rest for 165 seconds. 2 | Cupid can fly 8 km/s for 17 seconds, but then must rest for 114 seconds. 3 | Prancer can fly 18 km/s for 6 seconds, but then must rest for 103 seconds. 4 | Donner can fly 25 km/s for 6 seconds, but then must rest for 145 seconds. 5 | Dasher can fly 11 km/s for 12 seconds, but then must rest for 125 seconds. 6 | Comet can fly 21 km/s for 6 seconds, but then must rest for 121 seconds. 7 | Blitzen can fly 18 km/s for 3 seconds, but then must rest for 50 seconds. 8 | Vixen can fly 20 km/s for 4 seconds, but then must rest for 75 seconds. 9 | Dancer can fly 7 km/s for 20 seconds, but then must rest for 119 seconds. 10 | -------------------------------------------------------------------------------- /2015/input/15.txt: -------------------------------------------------------------------------------- 1 | Sprinkles: capacity 5, durability -1, flavor 0, texture 0, calories 5 2 | PeanutButter: capacity -1, durability 3, flavor 0, texture 0, calories 1 3 | Frosting: capacity 0, durability -1, flavor 4, texture 0, calories 6 4 | Sugar: capacity -1, durability 0, flavor 0, texture 2, calories 8 5 | -------------------------------------------------------------------------------- /2015/input/16tape.txt: -------------------------------------------------------------------------------- 1 | children: 3 2 | cats: 7 3 | samoyeds: 2 4 | pomeranians: 3 5 | akitas: 0 6 | vizslas: 0 7 | goldfish: 5 8 | trees: 3 9 | cars: 2 10 | perfumes: 1 11 | -------------------------------------------------------------------------------- /2015/input/17.txt: -------------------------------------------------------------------------------- 1 | 33 2 | 14 3 | 18 4 | 20 5 | 45 6 | 35 7 | 16 8 | 35 9 | 1 10 | 13 11 | 18 12 | 13 13 | 50 14 | 44 15 | 48 16 | 6 17 | 24 18 | 41 19 | 30 20 | 42 21 | -------------------------------------------------------------------------------- /2015/input/19.txt: -------------------------------------------------------------------------------- 1 | Al => ThF 2 | Al => ThRnFAr 3 | B => BCa 4 | B => TiB 5 | B => TiRnFAr 6 | Ca => CaCa 7 | Ca => PB 8 | Ca => PRnFAr 9 | Ca => SiRnFYFAr 10 | Ca => SiRnMgAr 11 | Ca => SiTh 12 | F => CaF 13 | F => PMg 14 | F => SiAl 15 | H => CRnAlAr 16 | H => CRnFYFYFAr 17 | H => CRnFYMgAr 18 | H => CRnMgYFAr 19 | H => HCa 20 | H => NRnFYFAr 21 | H => NRnMgAr 22 | H => NTh 23 | H => OB 24 | H => ORnFAr 25 | Mg => BF 26 | Mg => TiMg 27 | N => CRnFAr 28 | N => HSi 29 | O => CRnFYFAr 30 | O => CRnMgAr 31 | O => HP 32 | O => NRnFAr 33 | O => OTi 34 | P => CaP 35 | P => PTi 36 | P => SiRnFAr 37 | Si => CaSi 38 | Th => ThCa 39 | Ti => BP 40 | Ti => TiTi 41 | e => HF 42 | e => NAl 43 | e => OMg 44 | 45 | CRnCaSiRnBSiRnFArTiBPTiTiBFArPBCaSiThSiRnTiBPBPMgArCaSiRnTiMgArCaSiThCaSiRnFArRnSiRnFArTiTiBFArCaCaSiRnSiThCaCaSiRnMgArFYSiRnFYCaFArSiThCaSiThPBPTiMgArCaPRnSiAlArPBCaCaSiRnFYSiThCaRnFArArCaCaSiRnPBSiRnFArMgYCaCaCaCaSiThCaCaSiAlArCaCaSiRnPBSiAlArBCaCaCaCaSiThCaPBSiThPBPBCaSiRnFYFArSiThCaSiRnFArBCaCaSiRnFYFArSiThCaPBSiThCaSiRnPMgArRnFArPTiBCaPRnFArCaCaCaCaSiRnCaCaSiRnFYFArFArBCaSiThFArThSiThSiRnTiRnPMgArFArCaSiThCaPBCaSiRnBFArCaCaPRnCaCaPMgArSiRnFYFArCaSiThRnPBPMgAr 46 | -------------------------------------------------------------------------------- /2015/input/19_example.txt: -------------------------------------------------------------------------------- 1 | H => HO 2 | H => OH 3 | O => HH 4 | 5 | HOH 6 | -------------------------------------------------------------------------------- /2015/input/20.txt: -------------------------------------------------------------------------------- 1 | 29000000 2 | -------------------------------------------------------------------------------- /2015/input/21-shop.txt: -------------------------------------------------------------------------------- 1 | Weapons: Cost Damage Armor 2 | Dagger 8 4 0 3 | Shortsword 10 5 0 4 | Warhammer 25 6 0 5 | Longsword 40 7 0 6 | Greataxe 74 8 0 7 | 8 | Armor: Cost Damage Armor 9 | Leather 13 0 1 10 | Chainmail 31 0 2 11 | Splintmail 53 0 3 12 | Bandedmail 75 0 4 13 | Platemail 102 0 5 14 | 15 | Rings: Cost Damage Armor 16 | Damage+1 25 1 0 17 | Damage+2 50 2 0 18 | Damage+3 100 3 0 19 | Defense+1 20 0 1 20 | Defense+2 40 0 2 21 | Defense+3 80 0 3 22 | -------------------------------------------------------------------------------- /2015/input/21.txt: -------------------------------------------------------------------------------- 1 | Hit Points: 109 2 | Damage: 8 3 | Armor: 2 4 | -------------------------------------------------------------------------------- /2015/input/22.txt: -------------------------------------------------------------------------------- 1 | Hit Points: 51 2 | Damage: 9 3 | -------------------------------------------------------------------------------- /2015/input/23.txt: -------------------------------------------------------------------------------- 1 | jio a, +22 2 | inc a 3 | tpl a 4 | tpl a 5 | tpl a 6 | inc a 7 | tpl a 8 | inc a 9 | tpl a 10 | inc a 11 | inc a 12 | tpl a 13 | inc a 14 | inc a 15 | tpl a 16 | inc a 17 | inc a 18 | tpl a 19 | inc a 20 | inc a 21 | tpl a 22 | jmp +19 23 | tpl a 24 | tpl a 25 | tpl a 26 | tpl a 27 | inc a 28 | inc a 29 | tpl a 30 | inc a 31 | tpl a 32 | inc a 33 | inc a 34 | tpl a 35 | inc a 36 | inc a 37 | tpl a 38 | inc a 39 | tpl a 40 | tpl a 41 | jio a, +8 42 | inc b 43 | jie a, +4 44 | tpl a 45 | inc a 46 | jmp +2 47 | hlf a 48 | jmp -7 49 | -------------------------------------------------------------------------------- /2015/input/24.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 5 5 | 7 6 | 13 7 | 17 8 | 19 9 | 23 10 | 29 11 | 31 12 | 37 13 | 41 14 | 43 15 | 53 16 | 59 17 | 61 18 | 67 19 | 71 20 | 73 21 | 79 22 | 83 23 | 89 24 | 97 25 | 101 26 | 103 27 | 107 28 | 109 29 | 113 30 | -------------------------------------------------------------------------------- /2015/input/25.txt: -------------------------------------------------------------------------------- 1 | To continue, please consult the code grid in the manual. Enter the code at row 2947, column 3029. 2 | -------------------------------------------------------------------------------- /2015/input/4.txt: -------------------------------------------------------------------------------- 1 | ckczppom 2 | -------------------------------------------------------------------------------- /2015/input/9.txt: -------------------------------------------------------------------------------- 1 | Faerun to Norrath = 129 2 | Faerun to Tristram = 58 3 | Faerun to AlphaCentauri = 13 4 | Faerun to Arbre = 24 5 | Faerun to Snowdin = 60 6 | Faerun to Tambi = 71 7 | Faerun to Straylight = 67 8 | Norrath to Tristram = 142 9 | Norrath to AlphaCentauri = 15 10 | Norrath to Arbre = 135 11 | Norrath to Snowdin = 75 12 | Norrath to Tambi = 82 13 | Norrath to Straylight = 54 14 | Tristram to AlphaCentauri = 118 15 | Tristram to Arbre = 122 16 | Tristram to Snowdin = 103 17 | Tristram to Tambi = 49 18 | Tristram to Straylight = 97 19 | AlphaCentauri to Arbre = 116 20 | AlphaCentauri to Snowdin = 12 21 | AlphaCentauri to Tambi = 18 22 | AlphaCentauri to Straylight = 91 23 | Arbre to Snowdin = 129 24 | Arbre to Tambi = 53 25 | Arbre to Straylight = 40 26 | Snowdin to Tambi = 15 27 | Snowdin to Straylight = 99 28 | Tambi to Straylight = 70 29 | -------------------------------------------------------------------------------- /2016/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2016 2 | 3 | ![city](./img/city.png) 4 | -------------------------------------------------------------------------------- /2016/day/1.py: -------------------------------------------------------------------------------- 1 | with open('../input/1.txt') as f: 2 | data = f.read().strip().split(', ') 3 | 4 | zw = None 5 | xy = angle = 0 6 | visited = set() 7 | for direction, *steps in data: 8 | angle += 1 if direction == 'R' else -1 9 | for _ in range(int(''.join(steps))): 10 | xy += 1j**angle 11 | if zw is None and xy in visited: 12 | zw = xy 13 | visited.add(xy) 14 | 15 | print(int(abs(xy.real) + abs(xy.imag))) 16 | print(int(abs(zw.real) + abs(zw.imag))) 17 | -------------------------------------------------------------------------------- /2016/day/10.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | bot = defaultdict(list) 4 | output = defaultdict(list) 5 | children = {} 6 | 7 | with open('../input/10.txt') as f: 8 | for command, *args in map(str.split, f): 9 | if command == 'value': 10 | value, *_, index = args 11 | bot[int(index)].append(int(value)) 12 | else: 13 | index, _, _, _, x, low, *_, y, high = args 14 | children[int(index)] = f'{x}[{low}]', f'{y}[{high}]' 15 | 16 | while bot: 17 | for index, values in dict(bot).items(): 18 | if len(values) == 2: 19 | low, high = sorted(bot.pop(index)) 20 | lower, higher = children[index] 21 | eval(lower).append(low) 22 | eval(higher).append(high) 23 | if low == 17 and high == 61: 24 | print(index) 25 | 26 | print(output[0][0] * output[1][0] * output[2][0]) 27 | -------------------------------------------------------------------------------- /2016/day/12.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | 3 | 4 | @lru_cache 5 | def fib(n): 6 | return fib(n-1) + fib(n-2) if n > 2 else 1 7 | 8 | 9 | with open('../input/12.txt') as f: 10 | data = [[int(i) if i[-1].isdigit() else i for i in line[:-1].split()] 11 | for line in f] 12 | 13 | 14 | print(fib(data[2][1]+2) + int(data[16][1]) * int(data[17][1])) 15 | print(fib(data[2][1] + data[5][1] + 2) + data[16][1]*data[17][1]) 16 | -------------------------------------------------------------------------------- /2016/day/13.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | from heapq import heappop, heappush 3 | 4 | 5 | @lru_cache 6 | def grid(x, y): 7 | return bin(x*x + 3*x + 2*x*y + y + y*y + seed).count('1') % 2 8 | 9 | 10 | goal = 31 + 39j 11 | with open('../input/13.txt') as f: 12 | seed = int(f.read()) 13 | 14 | visitable_in_under_50_steps = 0 15 | to_visit = [] 16 | heappush(to_visit, (0, 1, 1)) # distance, x, y 17 | visited = set([(1, 1)]) 18 | while to_visit: 19 | distance, x, y = heappop(to_visit) 20 | if x == goal.real and y == goal.imag: 21 | break 22 | 23 | if distance <= 50: 24 | visitable_in_under_50_steps += 1 25 | 26 | xy = x + y * 1j 27 | for d in [1, -1, 1j, -1j]: 28 | zw = xy + d 29 | z, w = int(zw.real), int(zw.imag) 30 | if z >= 0 and w >= 0 and (z, w) not in visited and not grid(z, w): 31 | heappush(to_visit, (distance + 1, z, w)) 32 | visited.add((z, w)) 33 | 34 | print(distance) 35 | print(visitable_in_under_50_steps) 36 | -------------------------------------------------------------------------------- /2016/day/14.py: -------------------------------------------------------------------------------- 1 | from hashlib import md5 2 | from functools import lru_cache 3 | from itertools import count 4 | from collections import defaultdict 5 | 6 | import sys 7 | 8 | sys.setrecursionlimit(5000) 9 | 10 | 11 | @lru_cache 12 | def key(string, stretch=2016): 13 | hashed = md5(string.encode()).hexdigest() 14 | return hashed if not stretch else key(hashed, stretch - 1) 15 | 16 | 17 | with open('../input/14.txt') as f: 18 | salt = f.read()[:-1] 19 | 20 | keys = [] 21 | visited = set() 22 | matches = defaultdict(list) 23 | 24 | last_index = float('inf') 25 | for index in count(1): 26 | if index > last_index: 27 | break 28 | 29 | first_triple = True 30 | current, count = None, 0 31 | for char in key(salt + str(index)): 32 | if current is None: 33 | current = char 34 | 35 | if current == char: 36 | count += 1 37 | 38 | else: 39 | current = char 40 | count = 1 41 | 42 | if first_triple and count == 3: 43 | first_triple = False 44 | matches[char].append(index) 45 | 46 | if count == 5: 47 | for match in matches[char]: 48 | if 1000 >= index - match > 0 and match not in visited: 49 | visited.add(match) 50 | keys.append(match) 51 | if len(keys) == 64: 52 | last_index = match + 1000 53 | 54 | print(sorted(keys)[63]) 55 | -------------------------------------------------------------------------------- /2016/day/15.py: -------------------------------------------------------------------------------- 1 | import re 2 | from itertools import count 3 | 4 | 5 | with open('../input/15.txt') as f: 6 | discs = [list(map(int, re.findall(r'[0-9]+', line[:-1]))) 7 | for line in f] 8 | 9 | # discs.append([len(discs) + 1, 11, 0, 0]) # uncomment for part2 10 | 11 | print(next(time for time in count() 12 | if all((time + position + start) % mod == 0 13 | for position, mod, _, start in discs))) 14 | -------------------------------------------------------------------------------- /2016/day/16.py: -------------------------------------------------------------------------------- 1 | disk_length = 272 2 | # disk_length = 35651584 3 | 4 | with open('../input/16.txt') as f: 5 | disk = list(f.read()[:-1]) 6 | 7 | while len(disk) < disk_length: 8 | disk += ['0'] + ['0' if i == '1' else '1' for i in reversed(disk)] 9 | 10 | disk = disk[:disk_length] 11 | 12 | while len(disk) % 2 == 0: 13 | new_disk = [] 14 | for i, c in enumerate(disk[::2]): 15 | new_disk += '1' if c == disk[i*2 + 1] else '0' 16 | disk = new_disk 17 | 18 | print(''.join(disk)) 19 | -------------------------------------------------------------------------------- /2016/day/17.py: -------------------------------------------------------------------------------- 1 | from hashlib import md5 2 | from heapq import heappush, heappop 3 | 4 | 5 | with open('../input/17.txt') as f: 6 | code = f.read()[:-1] 7 | 8 | d = [(0, -1), (0, 1), (-1, 0), (1, 0)] 9 | letters = 'UDLR' 10 | to_visit = [(0, 0, 0, code)] 11 | first = last = None 12 | 13 | while to_visit: 14 | distance, x, y, code = heappop(to_visit) 15 | 16 | if x == y == 3: 17 | if first is None: 18 | first_solution = code[8:] 19 | last = len(code) - 8 20 | continue 21 | 22 | for i, c in enumerate(md5(code.encode()).hexdigest()[:4]): 23 | if c in 'cbdef': 24 | x_, y_ = x + d[i][0], y + d[i][1] 25 | if 4 > x_ > -1 and 4 > y_ > -1: 26 | heappush(to_visit, (distance+1, x_, y_, code + letters[i])) 27 | 28 | print(last) 29 | -------------------------------------------------------------------------------- /2016/day/18.py: -------------------------------------------------------------------------------- 1 | with open('../input/18.txt') as f: 2 | row = {i: c == '^' for i, c in enumerate(f.read()[:-1])} 3 | 4 | row_length = len(row) 5 | safe = row_length - sum(row.values()) 6 | row[-1] = row[row_length] = False 7 | 8 | for i in range(40 - 1): # replace 40 with 400000 for part 2 9 | new_row = {} 10 | for x in range(row_length): 11 | trap = row[x-1] and not row[x+1] or not row[x-1] and row[x+1] 12 | new_row[x] = trap 13 | safe += not trap 14 | 15 | row = new_row 16 | row[-1] = row[row_length] = False 17 | 18 | print(safe) 19 | -------------------------------------------------------------------------------- /2016/day/19.py: -------------------------------------------------------------------------------- 1 | with open('../input/19.txt') as f: 2 | n = int(f.read()) 3 | 4 | x = 1 5 | while x < n: 6 | x *= 2 7 | 8 | x /= 2 9 | print(int((n - x) * 2 + 1)) 10 | 11 | x = 1 12 | while x < n: 13 | x *= 3 14 | 15 | x /= 3 16 | print(int(n - x if n - x <= x else (n - 2*x)//2 + 1)) 17 | -------------------------------------------------------------------------------- /2016/day/2.py: -------------------------------------------------------------------------------- 1 | def walk(instructions): 2 | x = 13 3 | for i in instructions: 4 | x_ = x + move[i] 5 | if -1 < x_ < len(grid) and grid[x_] != '_': 6 | x = x_ 7 | 8 | return grid[x] 9 | 10 | 11 | move = {'R': 1, 'L': -1, 'U': -5, 'D': 5} 12 | 13 | with open('../input/2.txt') as f: 14 | lines = f.read().strip().splitlines() 15 | 16 | grid = '_____' '_123_' '_456_' '_789_' '_____' 17 | print(''.join(map(walk, lines))) 18 | 19 | grid = '__1__' '_234_' '56789' '_ABC_' '__D__' 20 | print(''.join(map(walk, lines))) 21 | -------------------------------------------------------------------------------- /2016/day/20.py: -------------------------------------------------------------------------------- 1 | with open('../input/20.txt') as f: 2 | ranges = list(sorted([list(map(int, line.split('-'))) for line in f])) 3 | 4 | ip = 0 5 | first = True 6 | whitelist = [] 7 | for low, high in ranges: 8 | for i, (low_, high_) in enumerate(whitelist): 9 | if low_ < low < high_: 10 | whitelist[i][0] = low + 1 11 | 12 | if low_ < high < high_: 13 | whitelist[i][1] = high - 1 14 | 15 | if ip >= high: 16 | continue 17 | 18 | if ip >= low: 19 | ip = high + 1 20 | 21 | else: 22 | if first: 23 | print(ip) 24 | first = False 25 | 26 | whitelist.append([ip, low-1]) 27 | ip = high + 1 28 | 29 | print(sum(high - low + 1 for low, high in whitelist if low <= high)) 30 | -------------------------------------------------------------------------------- /2016/day/21.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | part2 = False 4 | 5 | with open('../input/21.txt') as f: 6 | instructions = [line for line in f] 7 | 8 | word = list('abcdefgh') 9 | if part2: 10 | word = list('fbgdceah') 11 | instructions = reversed(instructions) 12 | 13 | for line in instructions: 14 | cmd, obj, left, *_, right = line.split() 15 | if cmd == 'swap': 16 | if obj == 'position': 17 | i, j = int(left), int(right) 18 | 19 | elif obj == 'letter': 20 | i, j = [i for i, c in enumerate(word) if c in {left, right}] 21 | 22 | word[i], word[j] = word[j], word[i] 23 | 24 | elif cmd == 'reverse': 25 | left, right = sorted(map(int, [left, right])) 26 | if left: 27 | word = word[:left] + word[right:left-1:-1] + word[right+1:] 28 | else: 29 | word = word[right::-1] + word[right+1:] 30 | 31 | elif cmd == 'rotate': 32 | tmp = deque(word) 33 | if obj == 'based': 34 | for i, c in enumerate(word): 35 | if c == right: 36 | break 37 | 38 | rotations = i + 1 + (i >= 4) 39 | if part2: 40 | rotations = {1: 1, 3: 2, 5: 3, 7: 4, 2: 6, 4: 7, 6: 8, 0: 1}[i] 41 | 42 | elif obj == 'left': 43 | rotations = -int(left) 44 | 45 | elif obj == 'right': 46 | rotations = int(left) 47 | 48 | if part2: 49 | rotations *= -1 50 | 51 | tmp.rotate(rotations) 52 | word = list(tmp) 53 | 54 | elif cmd == 'move': 55 | i, j = int(left), int(right) 56 | if part2: 57 | i, j = j, i 58 | 59 | c = word[i] 60 | del word[i] 61 | word.insert(j, c) 62 | 63 | print(''.join(word)) 64 | -------------------------------------------------------------------------------- /2016/day/22.py: -------------------------------------------------------------------------------- 1 | import re 2 | from heapq import heappop, heappush 3 | 4 | 5 | with open('../input/22.txt') as f: 6 | data = [list(map(int, re.findall(r'[0-9]+', line))) for line in f] 7 | 8 | xy, full = next((xy, size) for *xy, size, _, _, use in data[2:] if use == 0) 9 | nodes = {(x, y): (use <= full) + (use == 0) for x, y, _, use, *_ in data[2:]} 10 | print(sum(nodes.values()) - 2) 11 | 12 | max_x = max(x for x, *_ in data[2:]) 13 | to_visit = [] 14 | heappush(to_visit, (0, *xy)) 15 | visited = {(*xy)} 16 | while to_visit: 17 | distance, x, y = heappop(to_visit) 18 | if y == 0 and x == max_x: 19 | break 20 | 21 | for xy in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]: 22 | if xy in nodes and xy not in visited and nodes[xy]: 23 | heappush(to_visit, (distance+1, *xy)) 24 | visited.add(xy) 25 | 26 | print(distance + 5*(max_x-1)) 27 | -------------------------------------------------------------------------------- /2016/day/23.py: -------------------------------------------------------------------------------- 1 | from math import factorial as f 2 | 3 | with open('../input/23.txt') as fp: 4 | program = list(map(str.split, fp)) 5 | 6 | print(f(7) + int(program[19][1])*int(program[20][1])) 7 | print(f(12) + int(program[19][1])*int(program[20][1])) 8 | -------------------------------------------------------------------------------- /2016/day/24.py: -------------------------------------------------------------------------------- 1 | from heapq import heappush, heappop 2 | 3 | 4 | grid, keys = {}, {} 5 | with open('../input/24.txt') as f: 6 | for y, line in enumerate(f): 7 | for x, c in enumerate(line[:-1]): 8 | grid[x, y] = c 9 | if c not in '#.': 10 | keys[c] = (x, y) 11 | 12 | first = True 13 | to_visit = [] 14 | heappush(to_visit, (0, len(keys)-1, *keys['0'], frozenset('0'))) 15 | visited = set([(*keys['0'], frozenset('0'))]) 16 | while to_visit: 17 | distance, keys_left, x, y, keys_ = heappop(to_visit) 18 | if keys_left <= 0: 19 | if first: 20 | first = False 21 | print(distance) 22 | 23 | if (x, y) == keys['0']: 24 | break 25 | 26 | for z, w in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]: 27 | c = grid[z, w] 28 | if c != '#' and (z, w, keys_) not in visited: 29 | if c in keys and c not in keys_: 30 | heappush(to_visit, (distance+1, keys_left-1, z, w, keys_ | {c})) 31 | visited.add((z, w, keys_ | {c})) 32 | else: 33 | heappush(to_visit, (distance+1, keys_left, z, w, keys_)) 34 | visited.add((z, w, keys_)) 35 | 36 | print(distance) 37 | -------------------------------------------------------------------------------- /2016/day/25.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from itertools import count 3 | 4 | 5 | def to_int(x): 6 | return int(x) if x[-1].isdigit() else registers[x] 7 | 8 | 9 | with open('../input/25.txt') as f: 10 | program = [[code, args] for code, *args in map(str.split, f)] 11 | 12 | program_start = program[:] 13 | for i in count(1): 14 | ip = 0 15 | program = program_start[:] 16 | registers = defaultdict(int) 17 | registers['a'] = i 18 | output = 0 19 | while ip < len(program): 20 | if output >= 50: 21 | print(i) 22 | exit(i) 23 | 24 | code, args = program[ip] 25 | x = args[0] 26 | if len(args) > 1: 27 | y = args[1] 28 | 29 | if code == 'cpy': 30 | registers[y] = to_int(x) 31 | 32 | elif code == 'inc': 33 | registers[x] += 1 34 | 35 | elif code == 'dec': 36 | registers[x] -= 1 37 | 38 | elif code == 'jnz': 39 | if to_int(x) != 0: 40 | ip += to_int(y) 41 | continue 42 | 43 | elif code == 'tgl': 44 | x = to_int(x) + ip 45 | if x >= len(program): 46 | continue 47 | 48 | elif program[x][0] == 'inc': 49 | program[x][0] = 'dec' 50 | 51 | elif len(program[x][1]) == 1: 52 | program[x][0] = 'inc' 53 | 54 | elif program[x][0] == 'jnz': 55 | program[x][0] = 'cpy' 56 | 57 | elif len(program[x][1]) == 2: 58 | program[x][0] = 'jnz' 59 | 60 | elif code == 'out': 61 | if to_int(x) != output % 2: 62 | break 63 | 64 | output += 1 65 | 66 | ip += 1 67 | -------------------------------------------------------------------------------- /2016/day/3.py: -------------------------------------------------------------------------------- 1 | with open('../input/3.txt') as f: 2 | data = [list(map(int, args)) for args in map(str.split, f)] 3 | 4 | print(sum(0 < sum(sides) - 2*max(sides) for sides in data)) 5 | print(sum(0 < sum(sides) - 2*max(sides) 6 | for three_by_three in zip(data[::3], data[1::3], data[2::3]) 7 | for sides in zip(*three_by_three))) 8 | -------------------------------------------------------------------------------- /2016/day/4.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def common(soup): 5 | return set(sorted(set(soup), key=lambda c: (-soup.count(c), c))[:5]) 6 | 7 | 8 | def rot(soup, n): 9 | return ''.join(chr((ord(c) - 97 + int(n)) % 26 + 97) for c in soup) 10 | 11 | 12 | with open('../input/4.txt') as f: 13 | data = [re.split(r'-|\[', line[:-2]) for line in f] 14 | 15 | print(sum(int(n) for *abc, n, chk in data if set(chk) == common(''.join(abc)))) 16 | print(next(n for *abc, n, chk in data if 'north' in rot(''.join(abc), n))) 17 | -------------------------------------------------------------------------------- /2016/day/5.py: -------------------------------------------------------------------------------- 1 | from hashlib import md5 2 | from itertools import count 3 | 4 | with open("../input/5.txt") as f: 5 | data = f.read().strip() 6 | 7 | part1 = [] 8 | part2 = [-1]*8 9 | for i in count(): 10 | code = md5((data + str(i)).encode()).hexdigest() 11 | n = int(code[5], 16) 12 | if code.startswith('00000'): 13 | if len(part1) < 8: 14 | part1.append(code[5]) 15 | 16 | if 0 <= (n := int(code[5], 16)) <= 7 and part2[n] == -1: 17 | part2[n] = code[6] 18 | if -1 not in part2: 19 | break 20 | 21 | print(''.join(part1)) 22 | print(''.join(part2)) 23 | -------------------------------------------------------------------------------- /2016/day/6.py: -------------------------------------------------------------------------------- 1 | with open('../input/6.txt') as f: 2 | columns = list(zip(*f.read().splitlines())) 3 | 4 | print(''.join(max(set(c), key=c.count) for c in columns)) 5 | print(''.join(min(set(c), key=c.count) for c in columns)) 6 | -------------------------------------------------------------------------------- /2016/day/7.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | palindrom = re.compile(r'(\w)(?!\1)(\w)\2\1') 4 | aba_bab = re.compile(r'(\w)(?!\1)(\w)\1.*@.*\2\1\2') 5 | 6 | TLS = SSL = 0 7 | with open('../input/7.txt') as f: 8 | for line in f: 9 | segments = re.split(r'\[|\]', line[:-1]) 10 | outside = ' '.join(segments[::2]) 11 | inside = ' '.join(segments[1::2]) 12 | if re.search(palindrom, outside) and not re.search(palindrom, inside): 13 | TLS += 1 14 | 15 | if re.search(aba_bab, inside + '@' + outside): 16 | SSL += 1 17 | 18 | print(TLS) 19 | print(SSL) 20 | -------------------------------------------------------------------------------- /2016/day/8.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | with open('../input/8.txt') as f: 5 | lines = [line.split() for line in f] 6 | 7 | grid = np.zeros((6, 50)) 8 | for words in lines: 9 | if words[0] == 'rect': 10 | y, x = map(int, words[1].split('x')) 11 | grid[0: x, 0: y] = np.ones((x, y)) 12 | 13 | else: 14 | x, n = int(words[-3].split('=')[1]), int(words[-1]) 15 | if words[1] != 'row': 16 | grid = np.transpose(grid) 17 | 18 | grid[x] = np.roll(grid[x], n) 19 | 20 | if words[1] != 'row': 21 | grid = np.transpose(grid) 22 | 23 | print(int(np.sum(grid))) 24 | 25 | for line in grid: 26 | print(''.join(' ' if c == 0 else '#' for c in line)) 27 | -------------------------------------------------------------------------------- /2016/day/9.py: -------------------------------------------------------------------------------- 1 | def out(string): 2 | i, n = 0, 0 3 | while True: 4 | if i >= len(string): 5 | break 6 | 7 | if string[i] == '(': 8 | end = string.index(')', i) 9 | x, y = map(int, string[i + 1:end].split('x')) 10 | n += out(string[end + 1:end + 1 + x]) * y - 1 11 | # n += x*y - 1 12 | i = end + x 13 | i += 1 14 | n += 1 15 | return n 16 | 17 | 18 | with open('../input/9.txt') as f: 19 | data = f.read().strip() 20 | 21 | print(out(data)) 22 | -------------------------------------------------------------------------------- /2016/img/city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2016/img/city.png -------------------------------------------------------------------------------- /2016/input/1.txt: -------------------------------------------------------------------------------- 1 | R4, R4, L1, R3, L5, R2, R5, R1, L4, R3, L5, R2, L3, L4, L3, R1, R5, R1, L3, L1, R3, L1, R2, R2, L2, R5, L3, L4, R4, R4, R2, L4, L1, R5, L1, L4, R4, L1, R1, L2, R5, L2, L3, R2, R1, L194, R2, L4, R49, R1, R3, L5, L4, L1, R4, R2, R1, L5, R3, L5, L4, R4, R4, L2, L3, R78, L5, R4, R191, R4, R3, R1, L2, R1, R3, L1, R3, R4, R2, L2, R1, R4, L5, R2, L2, L4, L2, R1, R2, L3, R5, R2, L3, L3, R3, L1, L1, R5, L4, L4, L2, R5, R1, R4, L3, L5, L4, R5, L4, R5, R4, L3, L2, L5, R4, R3, L3, R1, L5, R5, R1, L3, R2, L5, R5, L3, R1, R4, L5, R4, R2, R3, L4, L5, R3, R4, L5, L5, R4, L4, L4, R1, R5, R3, L1, L4, L3, L4, R1, L5, L1, R2, R2, R4, R4, L5, R4, R1, L1, L1, L3, L5, L2, R4, L3, L5, L4, L1, R3 -------------------------------------------------------------------------------- /2016/input/11.txt: -------------------------------------------------------------------------------- 1 | The first floor contains a promethium generator and a promethium-compatible microchip. 2 | The second floor contains a cobalt generator, a curium generator, a ruthenium generator, and a plutonium generator. 3 | The third floor contains a cobalt-compatible microchip, a curium-compatible microchip, a ruthenium-compatible microchip, and a plutonium-compatible microchip. 4 | The fourth floor contains nothing relevant. 5 | -------------------------------------------------------------------------------- /2016/input/12.txt: -------------------------------------------------------------------------------- 1 | cpy 1 a 2 | cpy 1 b 3 | cpy 26 d 4 | jnz c 2 5 | jnz 1 5 6 | cpy 7 c 7 | inc d 8 | dec c 9 | jnz c -2 10 | cpy a c 11 | inc a 12 | dec b 13 | jnz b -2 14 | cpy c b 15 | dec d 16 | jnz d -6 17 | cpy 17 c 18 | cpy 18 d 19 | inc a 20 | dec d 21 | jnz d -2 22 | dec c 23 | jnz c -5 24 | -------------------------------------------------------------------------------- /2016/input/13.txt: -------------------------------------------------------------------------------- 1 | 1362 2 | -------------------------------------------------------------------------------- /2016/input/14.txt: -------------------------------------------------------------------------------- 1 | cuanljph 2 | -------------------------------------------------------------------------------- /2016/input/15.txt: -------------------------------------------------------------------------------- 1 | Disc #1 has 13 positions; at time=0, it is at position 1. 2 | Disc #2 has 19 positions; at time=0, it is at position 10. 3 | Disc #3 has 3 positions; at time=0, it is at position 2. 4 | Disc #4 has 7 positions; at time=0, it is at position 1. 5 | Disc #5 has 5 positions; at time=0, it is at position 3. 6 | Disc #6 has 17 positions; at time=0, it is at position 5. 7 | -------------------------------------------------------------------------------- /2016/input/16.txt: -------------------------------------------------------------------------------- 1 | 00111101111101000 2 | -------------------------------------------------------------------------------- /2016/input/17.txt: -------------------------------------------------------------------------------- 1 | pgflpeqp 2 | -------------------------------------------------------------------------------- /2016/input/18.txt: -------------------------------------------------------------------------------- 1 | ^..^^.^^^..^^.^...^^^^^....^.^..^^^.^.^.^^...^.^.^.^.^^.....^.^^.^.^.^.^.^.^^..^^^^^...^.....^....^. 2 | -------------------------------------------------------------------------------- /2016/input/19.txt: -------------------------------------------------------------------------------- 1 | 3014603 2 | -------------------------------------------------------------------------------- /2016/input/23.txt: -------------------------------------------------------------------------------- 1 | cpy a b 2 | dec b 3 | cpy a d 4 | cpy 0 a 5 | cpy b c 6 | inc a 7 | dec c 8 | jnz c -2 9 | dec d 10 | jnz d -5 11 | dec b 12 | cpy b c 13 | cpy c d 14 | dec d 15 | inc c 16 | jnz d -2 17 | tgl c 18 | cpy -16 c 19 | jnz 1 c 20 | cpy 86 c 21 | jnz 78 d 22 | inc a 23 | inc d 24 | jnz d -2 25 | inc c 26 | jnz c -5 27 | -------------------------------------------------------------------------------- /2016/input/25.txt: -------------------------------------------------------------------------------- 1 | cpy a d 2 | cpy 15 c 3 | cpy 170 b 4 | inc d 5 | dec b 6 | jnz b -2 7 | dec c 8 | jnz c -5 9 | cpy d a 10 | jnz 0 0 11 | cpy a b 12 | cpy 0 a 13 | cpy 2 c 14 | jnz b 2 15 | jnz 1 6 16 | dec b 17 | dec c 18 | jnz c -4 19 | inc a 20 | jnz 1 -7 21 | cpy 2 b 22 | jnz c 2 23 | jnz 1 4 24 | dec b 25 | dec c 26 | jnz 1 -4 27 | jnz 0 0 28 | out b 29 | jnz a -19 30 | jnz 1 -21 31 | -------------------------------------------------------------------------------- /2016/input/5.txt: -------------------------------------------------------------------------------- 1 | uqwqemis 2 | -------------------------------------------------------------------------------- /2017/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2017 2 | 3 | ![circuit](./img/circuit.png) 4 | -------------------------------------------------------------------------------- /2017/day/1.py: -------------------------------------------------------------------------------- 1 | with open('../input/1.txt') as f: 2 | data = map(int, list(f.read().strip())) 3 | 4 | print sum(data[i] for i in range(len(data)) if data[i] == data[i - 1]) 5 | print sum(data[i] for i in range(len(data)) if data[i] == data[(i + len(data) / 2) % len(data)]) 6 | -------------------------------------------------------------------------------- /2017/day/10.py: -------------------------------------------------------------------------------- 1 | def solve(data, part1): 2 | length = 256 3 | L = range(length) 4 | i = skip = 0 5 | for k in xrange(64): 6 | for num in data: 7 | for j in xrange(length): 8 | L.append(L[j]) 9 | tmp = [] 10 | for j in L: 11 | tmp.append(j) 12 | for j in xrange(i, num + i): 13 | L[j] = tmp[num + 2 * i - j - 1] 14 | if num+i > length - 1: 15 | for j in xrange(0, num + i - length): 16 | L[j] = L[length + j] 17 | L = L[:length] 18 | i += skip + num 19 | skip += 1 20 | if i > length - 1: 21 | i %= length 22 | if part1: 23 | part1 = False 24 | print L[0] * L[1] 25 | return 26 | hash = "" 27 | for i in xrange(16): 28 | tmp = 0 29 | for j in xrange(16): 30 | tmp ^= L[16 * i + j] 31 | hash += format(tmp, '02x') 32 | print hash 33 | 34 | with open("../input/10.txt") as f: 35 | tmp = f.read().strip() 36 | data1 = [int(i) for i in tmp.split(',')] 37 | data2 = [ord(i) for i in list(tmp)] + [17, 31, 73, 47, 23] 38 | 39 | solve(data2, solve(data1, True)) 40 | -------------------------------------------------------------------------------- /2017/day/11.py: -------------------------------------------------------------------------------- 1 | with open("../input/11.txt") as f: 2 | data = f.read().split(',') 3 | 4 | x = y = z = sol = 0 5 | for card in data: 6 | if card == 'n': y += 1; z -= 1 7 | elif card == 's': y -= 1; z += 1 8 | elif card == 'ne': x += 1; z -= 1 9 | elif card == 'sw': x -= 1; z += 1 10 | elif card == 'nw': x -= 1; y += 1 11 | elif card == 'se': x += 1; y -= 1 12 | dist = (abs(x) + abs(y) + abs(z)) / 2 13 | sol = dist if sol < dist else sol 14 | 15 | print (abs(x) + abs(y) + abs(z)) / 2 16 | print sol 17 | -------------------------------------------------------------------------------- /2017/day/12.py: -------------------------------------------------------------------------------- 1 | with open("../input/12.txt") as f: 2 | pipes = [line[:-1].replace('<->', '').replace(',', '').split() for line in f.readlines()] 3 | 4 | groups = [] 5 | for pipe in pipes: 6 | tmpS = set(pipe) 7 | tmpD = {} 8 | for i in xrange(len(groups)): 9 | if len(tmpS.intersection(groups[i])) > 0: 10 | tmpD[i] = groups[i] 11 | if len(tmpD) == 0: 12 | groups.append(tmpS) 13 | else: 14 | tmpA = [] 15 | j = 0 16 | for i in tmpD: 17 | del groups[i - j] 18 | tmpA += tmpD[i] 19 | j += 1 20 | groups.append(set(tmpA).union(tmpS)) 21 | 22 | for group in groups: 23 | if '0' in group: 24 | print len(group) 25 | print len(groups) 26 | 27 | 28 | -------------------------------------------------------------------------------- /2017/day/13.py: -------------------------------------------------------------------------------- 1 | with open("../input/13.txt") as f: 2 | data = [map(int, i[:-1].split(': ')) for i in f.readlines()] 3 | 4 | print sum(x * y if x % (y * 2 - 2) == 0 else 0 for x, y in data) 5 | 6 | i = 0 7 | while True: 8 | part2 = True 9 | for x, y in data: 10 | if i + y != 0 and (x + i) % (y * 2 - 2) == 0: 11 | part2 = False 12 | break 13 | if part2: 14 | print i 15 | break 16 | i += 1 17 | -------------------------------------------------------------------------------- /2017/day/14.py: -------------------------------------------------------------------------------- 1 | # Day 10 2 | def bits(data): 3 | length = 256 4 | L = range(length) 5 | i = skip = 0 6 | for k in xrange(64): 7 | for num in data: 8 | for j in xrange(length): 9 | L.append(L[j]) 10 | tmp = [] 11 | for j in L: 12 | tmp.append(j) 13 | for j in xrange(i, num + i): 14 | L[j] = tmp[num + 2 * i - j - 1] 15 | if num + i > length - 1: 16 | for j in xrange(0, num + i - length): 17 | L[j] = L[length + j] 18 | L = L[:length] 19 | i += (skip + num) 20 | skip += 1 21 | if i > length - 1: i %= length 22 | 23 | hash = "" 24 | for i in xrange(16): 25 | tmp = 0 26 | for j in xrange(16): 27 | tmp ^= L[16 * i + j] 28 | hash += format(tmp, '02x') 29 | s = "" 30 | for i in xrange(128 - len(bin(int(hash, 16))[2:])): 31 | s += '0' 32 | return s + bin(int(hash, 16))[2:] 33 | 34 | # Day 14 35 | def group(i, j, num): 36 | global grid 37 | grid[i][j][1] = num 38 | if i != 0 and grid[i - 1][j][0] == 1 and grid[i - 1][j][1] == 0: group(i - 1, j, num) 39 | if i != 127 and grid[i + 1][j][0] == 1 and grid[i + 1][j][1] == 0: group(i + 1, j, num) 40 | if j != 0 and grid[i][j - 1][0] == 1 and grid[i][j - 1][1] == 0: group(i, j - 1, num) 41 | if j != 127 and grid[i][j + 1][0] == 1 and grid[i][j + 1][1] == 0: group(i, j + 1, num) 42 | 43 | with open("../input/14.txt") as f: 44 | data = f.read() 45 | 46 | num = cnt = 0 47 | grid = [] 48 | for row in range(128): 49 | binRow = bits([ord(i) for i in list(data + '-' + str(row))] + [17, 31, 73, 47, 23]) 50 | for i in binRow: 51 | if i == '1': cnt += 1 52 | grid.append([[int(x),0] for x in list(binRow)]) 53 | print cnt 54 | for i in xrange(128): 55 | for j in xrange(128): 56 | if grid[i][j][0] == 1 and grid[i][j][1] == 0: 57 | num += 1 58 | group(i,j,num) 59 | 60 | print num 61 | -------------------------------------------------------------------------------- /2017/day/15.py: -------------------------------------------------------------------------------- 1 | def gen(data, part): 2 | while True: 3 | data[0] = data[0] * data[1] % data[2] 4 | if data[0] % (1 if part == 1 else data[3]) == 0: 5 | yield data[0] & 0xFFFF 6 | 7 | with open("../input/15.txt") as f: 8 | tmp = [16807, 4, 48271, 8] 9 | data = {x.split()[1]: [int(x.split()[-1]), tmp.pop(0), 2147483647, tmp.pop(0)] for x in f.readlines()} 10 | 11 | cnt = 0 12 | A, B = gen(list(data['A']), 1), gen(list(data['B']), 1) 13 | for i in xrange(40000000): 14 | if next(A) == next(B): 15 | cnt += 1 16 | 17 | print cnt 18 | cnt = 0 19 | A, B = gen(list(data['A']), 2), gen(list(data['B']), 2) 20 | for i in xrange(5000000): 21 | if next(A) == next(B): 22 | cnt += 1 23 | 24 | print cnt 25 | -------------------------------------------------------------------------------- /2017/day/16.py: -------------------------------------------------------------------------------- 1 | with open ("../input/16.txt") as f: 2 | data = f.read().split(',') 3 | 4 | def solution(cap): 5 | p = list('abcdefghijklmnop') 6 | old = [] 7 | for i in xrange(cap): 8 | if ''.join(p) in old: 9 | print(old[cap % i]) 10 | return 11 | old.append(''.join(p)) 12 | for ins in data: 13 | if ins[0] == 's': 14 | a = int(ins[1:]) 15 | p = p[-a:] + p[:-a] 16 | elif ins[0] == 'x': 17 | a, b = map(int, ins[1:].split('/')) 18 | p[b], p[a] = p[a], p[b] 19 | elif ins[0] == 'p': 20 | a, b = map(int, map(p.index, ins[1:].split('/'))) 21 | p[b], p[a] = p[a], p[b] 22 | print(''.join(p)) 23 | 24 | solution(1) 25 | solution(1000000000) 26 | -------------------------------------------------------------------------------- /2017/day/17.py: -------------------------------------------------------------------------------- 1 | with open("../input/17.txt") as f: 2 | data = int(f.read()) 3 | 4 | L = [0] 5 | pos = 0 6 | for i in xrange(2017): 7 | pos = (pos + data) % len(L) 8 | L = L[:pos + 1] + [i + 1] + L[pos + 1:] 9 | pos += 1 10 | print L[pos + 1] 11 | 12 | l = 1 13 | pos = 0 14 | for i in xrange(50000000): 15 | pos = (pos + data) % l 16 | if pos == 0: 17 | part2 = i + 1 18 | l += 1 19 | pos += 1 20 | print part2 21 | -------------------------------------------------------------------------------- /2017/day/18.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def run(instructions, p=0): 4 | i, reg = 0, {'p': p} 5 | while True: 6 | code, *args = instructions[i] 7 | num = lambda x: int(x) if x[-1].isdigit() else reg.get(x, 0) 8 | arg = lambda x: num(args[x-1]) 9 | if code == 'snd': queue[p].append(sound := arg(1)) 10 | elif code == 'set': reg[args[0]] = arg(2) 11 | elif code == 'add': reg[args[0]] = arg(1) + arg(2) 12 | elif code == 'mul': reg[args[0]] = arg(1) * arg(2) 13 | elif code == 'mod': reg[args[0]] = arg(1) % arg(2) 14 | elif code == 'rcv': reg[args[0]] = yield 15 | elif code == 'jgz': i += arg(2)-1 if arg(1) > 0 else 0 16 | i += 1 17 | 18 | with open("../input/18.txt") as f: 19 | data = list(map(str.split, f)) 20 | 21 | counter = 0 22 | queue = [deque([]), deque([])] 23 | next(program0 := run(data, 0)) 24 | next(program1 := run(data, 1)) 25 | print(queue[0][-1]) 26 | 27 | while queue[0] or queue[1]: 28 | if queue[0]: 29 | program1.send(queue[0].popleft()) 30 | if queue[1]: 31 | counter += 1 32 | program0.send(queue[1].popleft()) 33 | 34 | print(counter) 35 | -------------------------------------------------------------------------------- /2017/day/19.py: -------------------------------------------------------------------------------- 1 | with open('../input/19.txt') as f: 2 | grid = {x+y*1j: c for y, l in enumerate(f) for x, c in enumerate(l)} 3 | 4 | xy = next(xy for xy in grid if xy.imag == 0 and grid[xy] != ' ') 5 | block = {1: '-', -1: '-', 1j: '|', -1j: '|'} 6 | letters = '' 7 | steps = 0 8 | d = 1j 9 | while grid[xy] != ' ': 10 | if grid[xy] in 'QWERTYUIOPASDFGHJKLZXCVBNM': 11 | letters += grid[xy] 12 | 13 | if grid[xy] == '+': 14 | d *= 1j if grid[xy+d*1j] == block[d*1j] else 1j**-1 15 | 16 | xy += d 17 | steps += 1 18 | 19 | print(letters) 20 | print(steps) 21 | -------------------------------------------------------------------------------- /2017/day/2.py: -------------------------------------------------------------------------------- 1 | with open("../input/2.txt") as f: 2 | rows = [map(int, i.split()) for i in f.readlines()] 3 | 4 | print(sum(max(row) - min(row) for row in rows)) 5 | print(sum(a / b for row in rows for a in row for b in row if (a % b == 0 and a != b))) 6 | -------------------------------------------------------------------------------- /2017/day/20.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import defaultdict 3 | 4 | magic = lambda point: tuple(zip(*zip(*[iter(point)]*3))) 5 | with open('../input/20.txt') as f: 6 | points = [map(int, re.findall('-?\d+', line)) for line in f] 7 | points = list(map(magic, points)) 8 | 9 | t = 1000 # TODO code an algebraic solution 10 | 11 | print(min((sum((s + v*t + a*t**2)**2 for s, v, a in point)**1/2, i) 12 | for i, point in enumerate(points))[1]) 13 | 14 | for _ in range(t): 15 | position = defaultdict(list) 16 | for i, point in enumerate(points): 17 | points[i] = tuple((s+v+a, v+a, a) for s, v, a in point) 18 | point = next(zip(*points[i])) 19 | position[point].append(i) 20 | remove = [i for l in position.values() for i in l if len(l) > 1] 21 | for i in sorted(remove, reverse=True): 22 | del points[i] 23 | 24 | print(len(points)) 25 | -------------------------------------------------------------------------------- /2017/day/21.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | def comb2(x): 4 | comb = [x] 5 | for _ in range(4): 6 | i, j, _, k, l = comb[-1] 7 | comb.append(j+i+'/'+l+k) # flip 8 | comb.append(k+i+'/'+l+j) # rotate 9 | return comb[1:] 10 | 11 | def comb3(x): 12 | comb = [x] 13 | for _ in range(4): 14 | a, b, c, _, d, e, f, _, g, h, i = comb[-1] 15 | comb.append(g+h+i+'/'+d+e+f+'/'+a+b+c) # flip 16 | comb.append(c+b+a+'/'+f+e+d+'/'+i+h+g) # flip 17 | comb.append(g+d+a+'/'+h+e+b+'/'+i+f+c) # rotate 18 | return comb[1:] 19 | 20 | data = {} 21 | with open('../input/21.txt') as f: 22 | for line in f: 23 | x, y = line[:-1].split(' => ') 24 | comb = comb2(x) if len(x) == 5 else comb3(x) 25 | for x in comb: 26 | data[x] = y 27 | 28 | grid = {0: '.#.', 1: '..#', 2: '###'} 29 | for i in range(1, 19): 30 | size = len(grid[0]) 31 | mod = 3 if size%2 else 2 32 | next_grid = defaultdict(str) 33 | 34 | for y in range(0, size, mod): 35 | for x in range(0, size, mod): 36 | block = '/'.join(grid[y+dy][x:x+mod] for dy in range(mod)) 37 | for dy, line in enumerate(data[block].split('/')): 38 | next_grid[y//mod*(mod+1)+dy] += line 39 | 40 | grid = next_grid 41 | if i == 5 or i == 18: 42 | print(sum(c == '#' for c in ''.join(grid.values()))) 43 | -------------------------------------------------------------------------------- /2017/day/22.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | with open('../input/22.txt') as f: 4 | grid = defaultdict(int, {x+y*1j: (c=='#')*2 for y, l in enumerate(f) 5 | for x, c in enumerate(l[:-1])}) 6 | d = -1j 7 | counter = 0 8 | xy = (1+1j) * ((len(grid)**(1/2))//2) 9 | for burst in range(10000000): 10 | d *= 1j**(4-(grid[xy]^1)) 11 | grid[xy] = (grid[xy]+1)%4 12 | if grid[xy] == 2: 13 | counter += 1 14 | xy += d 15 | 16 | print(counter) 17 | -------------------------------------------------------------------------------- /2017/day/23.py: -------------------------------------------------------------------------------- 1 | with open('../input/23.txt') as f: 2 | b = next(int(line[5:]) for line in f if line[:5] == 'set b') 3 | 4 | print((b-2)**2) 5 | 6 | counter = 0 7 | b = b*100 + 100000 8 | for i in range(b, b+17001, 17): 9 | for j in range(2, int(i**(1/2))): 10 | if i % j == 0: 11 | counter += 1 12 | break 13 | 14 | print(counter) 15 | -------------------------------------------------------------------------------- /2017/day/24.py: -------------------------------------------------------------------------------- 1 | def find(data, port): 2 | if not any(port in p for p in data): 3 | return 0, port 4 | 5 | s = lambda x, y: tuple(map(sum, zip(x, y))) 6 | return s((1, 2*port), max((find(data-{p}, p[port == p[0]]) 7 | # for p in data if port in p), key=lambda x: x[1])) # part 1 8 | for p in data if port in p))) # part 2 9 | 10 | 11 | with open('../input/24.txt') as f: 12 | data = set(tuple(map(int, line.split('/'))) for line in f) 13 | 14 | print(find(data, 0)[1]) 15 | -------------------------------------------------------------------------------- /2017/day/25.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | states = {} 4 | with open('../input/25.txt') as f: 5 | data = f.read().split('\n\n') 6 | state = data[0][15] 7 | steps = int(next(w for w in data[0].split() if w.isdigit())) 8 | for block in data[1:]: 9 | l = block.split('\n') 10 | states[l[0][-2]] = ((int(l[2][-2]), l[3][27], l[4][-2]), 11 | (int(l[6][-2]), l[7][27], l[8][-2])) 12 | 13 | tape = defaultdict(bool) 14 | x = 0 15 | for _ in range(steps): 16 | value, direction, state = states[state][tape[x]] 17 | tape[x] = value 18 | x += 1 if direction == 'r' else -1 19 | 20 | print(sum(tape.values())) 21 | -------------------------------------------------------------------------------- /2017/day/3.py: -------------------------------------------------------------------------------- 1 | # part2 initially done by hand, here is one neat solution inspired by /u/akho_ 2 | from math import sqrt 3 | 4 | def nex(x, y): 5 | if x == y == 0: return 1, 0 6 | if x > -y and x > y: return x, y + 1 7 | if x > -y and x <= y: return x - 1, y 8 | if x <= -y and x < y: return x, y - 1 9 | if x <= -y and x >= y: return x + 1, y 10 | 11 | with open('../input/3.txt') as f: 12 | data = int(f.read().strip()) 13 | 14 | x = int(sqrt(data)) + 1 15 | print (x - 1) / 2 - (data - (x * x - x + 1)) + x / 2 16 | 17 | x = y = 0 18 | m = {(0, 0): 1} 19 | while m[(x, y)] <= data: 20 | x, y = nex(x, y) 21 | m[(x, y)] = sum(m.get((x + i, y + j), 0) for i in [-1, 0, 1] for j in [0, 1, -1]) 22 | print m[(x, y)] 23 | -------------------------------------------------------------------------------- /2017/day/4.py: -------------------------------------------------------------------------------- 1 | with open('../input/4.txt') as f: 2 | data = [i.split() for i in f.readlines()] 3 | 4 | print sum(1 for i in data if len(i) == len(set(i))) 5 | print sum(1 for i in data if len(i) == len(set(i)) 6 | and all(j == k or set(j) != set(k) for j in i for k in i)) 7 | -------------------------------------------------------------------------------- /2017/day/5.py: -------------------------------------------------------------------------------- 1 | with open('../input/5.txt') as f: 2 | data = map(int, f.readlines()) 3 | 4 | pc = steps = 0 5 | while pc < len(data): 6 | num = 1 # if data[pc] < 3 else -1 7 | data[pc] += num 8 | pc += data[pc] - num 9 | steps += 1 10 | print steps 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /2017/day/6.py: -------------------------------------------------------------------------------- 1 | def solve(block): 2 | count, seen = 0, set() 3 | while not seen.intersection({tuple(block)}): 4 | count += 1 5 | seen.add(tuple(block)) 6 | top = max(block) 7 | i = block.index(top) 8 | block[i] = 0 9 | for j in xrange(top): 10 | block[(i + j + 1) % len(block)] += 1 11 | print count 12 | return block 13 | 14 | with open("../input/6.txt") as f: 15 | block = map(int, f.read().strip().split()) 16 | 17 | solve(solve(block)) 18 | -------------------------------------------------------------------------------- /2017/day/7.py: -------------------------------------------------------------------------------- 1 | from itertools import chain 2 | 3 | f = open('../input/7.txt').readlines() 4 | kids = dict((i.split()[0], i[:-1].replace('-> ', '').replace(',', '').split()[2:]) for i in f) 5 | weight = dict((i.split()[0], int(i.split()[1].replace(')', '').replace('(', ''))) for i in f) 6 | 7 | print set(kids).difference(set(chain(*kids.values()))).pop() 8 | 9 | total = dict((kid, -float('inf')) for kid in kids) 10 | while sum(total.values()) == -float('inf'): 11 | parent = kids.keys()[0] 12 | children = kids.pop(parent) 13 | above = [total[child] for child in children] 14 | total[parent] = weight[parent] + sum(above) 15 | if total[parent] == -float('inf'): 16 | kids[parent] = children 17 | elif len(above) and above.count(above[0]) != len(above): 18 | node = [x for x in children if above.count(total[x]) == 1].pop() 19 | print weight[node] + sum(set(above)) - 2 * total[node] 20 | break 21 | -------------------------------------------------------------------------------- /2017/day/8.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | with open("../input/8.txt") as f: 4 | data = f.read().replace('\n', ' else 0\n').replace('inc', '+=').replace('dec', '-=') 5 | 6 | m, d = 0, defaultdict(int) 7 | for line in data.splitlines(): 8 | exec(line, {}, d) 9 | m = max(m, max(d.values())) 10 | 11 | print max(d.values()) 12 | print m 13 | -------------------------------------------------------------------------------- /2017/day/9.py: -------------------------------------------------------------------------------- 1 | with open("../input/9.txt") as f: 2 | data = list(f.read().replace('\n', '')) 3 | 4 | i = lvl = depth = garbage = 0 5 | ExFlag = GaFlag = False 6 | while i < len(data): 7 | if data[i] == '{' and not GaFlag: depth += 1 8 | elif data[i] == '}' and not GaFlag: lvl += depth; depth -= 1 9 | elif data[i] == '<' and not GaFlag: GaFlag = True 10 | elif data[i] == '>' and GaFlag: GaFlag = False 11 | elif data[i] == '!' and GaFlag: i += 1 12 | elif GaFlag: garbage += 1 13 | i += 1 14 | 15 | print lvl 16 | print garbage 17 | -------------------------------------------------------------------------------- /2017/img/circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2017/img/circuit.png -------------------------------------------------------------------------------- /2017/input/10.txt: -------------------------------------------------------------------------------- 1 | 189,1,111,246,254,2,0,120,215,93,255,50,84,15,94,62 -------------------------------------------------------------------------------- /2017/input/13.txt: -------------------------------------------------------------------------------- 1 | 0: 3 2 | 1: 2 3 | 2: 4 4 | 4: 4 5 | 6: 5 6 | 8: 6 7 | 10: 8 8 | 12: 8 9 | 14: 6 10 | 16: 6 11 | 18: 9 12 | 20: 8 13 | 22: 6 14 | 24: 10 15 | 26: 12 16 | 28: 8 17 | 30: 8 18 | 32: 14 19 | 34: 12 20 | 36: 8 21 | 38: 12 22 | 40: 12 23 | 42: 12 24 | 44: 12 25 | 46: 12 26 | 48: 14 27 | 50: 12 28 | 52: 12 29 | 54: 10 30 | 56: 14 31 | 58: 12 32 | 60: 14 33 | 62: 14 34 | 64: 14 35 | 66: 14 36 | 68: 14 37 | 70: 14 38 | 72: 14 39 | 74: 20 40 | 78: 14 41 | 80: 14 42 | 90: 17 43 | 96: 18 44 | -------------------------------------------------------------------------------- /2017/input/14.txt: -------------------------------------------------------------------------------- 1 | hwlqcszp -------------------------------------------------------------------------------- /2017/input/15.txt: -------------------------------------------------------------------------------- 1 | Generator A starts with 289 2 | Generator B starts with 629 3 | -------------------------------------------------------------------------------- /2017/input/17.txt: -------------------------------------------------------------------------------- 1 | 349 -------------------------------------------------------------------------------- /2017/input/18.txt: -------------------------------------------------------------------------------- 1 | set i 31 2 | set a 1 3 | mul p 17 4 | jgz p p 5 | mul a 2 6 | add i -1 7 | jgz i -2 8 | add a -1 9 | set i 127 10 | set p 464 11 | mul p 8505 12 | mod p a 13 | mul p 129749 14 | add p 12345 15 | mod p a 16 | set b p 17 | mod b 10000 18 | snd b 19 | add i -1 20 | jgz i -9 21 | jgz a 3 22 | rcv b 23 | jgz b -1 24 | set f 0 25 | set i 126 26 | rcv a 27 | rcv b 28 | set p a 29 | mul p -1 30 | add p b 31 | jgz p 4 32 | snd a 33 | set a b 34 | jgz 1 3 35 | snd b 36 | set f 1 37 | add i -1 38 | jgz i -11 39 | snd a 40 | jgz f -16 41 | jgz a -19 -------------------------------------------------------------------------------- /2017/input/2.txt: -------------------------------------------------------------------------------- 1 | 278 1689 250 1512 1792 1974 175 1639 235 1635 1690 1947 810 224 928 859 2 | 160 50 55 81 68 130 145 21 211 136 119 78 174 155 149 72 3 | 4284 185 4499 273 4750 4620 4779 4669 2333 231 416 1603 197 922 5149 2993 4 | 120 124 104 1015 1467 110 299 320 1516 137 1473 132 1229 1329 1430 392 5 | 257 234 3409 2914 2993 3291 368 284 259 3445 245 1400 3276 339 2207 233 6 | 1259 78 811 99 2295 1628 3264 2616 116 3069 2622 1696 1457 1532 268 82 7 | 868 619 139 522 168 872 176 160 1010 200 974 1008 1139 552 510 1083 8 | 1982 224 3003 234 212 1293 1453 3359 326 3627 3276 3347 1438 2910 248 2512 9 | 4964 527 5108 4742 4282 4561 4070 3540 196 228 3639 4848 152 1174 5005 202 10 | 1381 1480 116 435 980 1022 155 1452 1372 121 128 869 1043 826 1398 137 11 | 2067 2153 622 1479 2405 1134 2160 1057 819 99 106 1628 1538 108 112 1732 12 | 4535 2729 4960 241 4372 3960 248 267 230 5083 827 1843 3488 4762 2294 3932 13 | 3245 190 2249 2812 2620 2743 2209 465 139 2757 203 2832 2454 177 2799 2278 14 | 1308 797 498 791 1312 99 1402 1332 521 1354 1339 101 367 1333 111 92 15 | 149 4140 112 3748 148 815 4261 138 1422 2670 32 334 2029 4750 4472 2010 16 | 114 605 94 136 96 167 553 395 164 159 284 104 530 551 544 18 17 | -------------------------------------------------------------------------------- /2017/input/22.txt: -------------------------------------------------------------------------------- 1 | .......##.#..####.#....## 2 | ..###....###.####..##.##. 3 | #..####.#....#.#....##... 4 | .#....#.#.#....#######... 5 | .###..###.#########....## 6 | ##...#####..#####.###.#.. 7 | .#..##.###.#.#....######. 8 | .#.##.#..####..#.##.....# 9 | #.#..###..##..#......##.# 10 | ##.###.##.#.#...##.#.##.. 11 | ##...#.######.#..##.#...# 12 | ....#.####..#..###.##..## 13 | ...#....#.###.#.#..#..... 14 | ..###.#.#....#.....#.#### 15 | .#....##..##.#.#...#.#.#. 16 | ...##.#.####.###.##...#.# 17 | ##.#.####.#######.##..##. 18 | .##...#......####..####.# 19 | #..###.#.###.##.#.#.##..# 20 | #..###.#.#.#.#.#....#.#.# 21 | ####.#..##..#.#..#..#.### 22 | ##.....#..#.#.#..#.####.. 23 | #####.....###.........#.. 24 | ##...#...####..#####...## 25 | .....##.#....##...#.....# 26 | -------------------------------------------------------------------------------- /2017/input/23.txt: -------------------------------------------------------------------------------- 1 | set b 84 2 | set c b 3 | jnz a 2 4 | jnz 1 5 5 | mul b 100 6 | sub b -100000 7 | set c b 8 | sub c -17000 9 | set f 1 10 | set d 2 11 | set e 2 12 | set g d 13 | mul g e 14 | sub g b 15 | jnz g 2 16 | set f 0 17 | sub e -1 18 | set g e 19 | sub g b 20 | jnz g -8 21 | sub d -1 22 | set g d 23 | sub g b 24 | jnz g -13 25 | jnz f 2 26 | sub h -1 27 | set g b 28 | sub g c 29 | jnz g 2 30 | jnz 1 3 31 | sub b -17 32 | jnz 1 -23 33 | -------------------------------------------------------------------------------- /2017/input/24.txt: -------------------------------------------------------------------------------- 1 | 14/42 2 | 2/3 3 | 6/44 4 | 4/10 5 | 23/49 6 | 35/39 7 | 46/46 8 | 5/29 9 | 13/20 10 | 33/9 11 | 24/50 12 | 0/30 13 | 9/10 14 | 41/44 15 | 35/50 16 | 44/50 17 | 5/11 18 | 21/24 19 | 7/39 20 | 46/31 21 | 38/38 22 | 22/26 23 | 8/9 24 | 16/4 25 | 23/39 26 | 26/5 27 | 40/40 28 | 29/29 29 | 5/20 30 | 3/32 31 | 42/11 32 | 16/14 33 | 27/49 34 | 36/20 35 | 18/39 36 | 49/41 37 | 16/6 38 | 24/46 39 | 44/48 40 | 36/4 41 | 6/6 42 | 13/6 43 | 42/12 44 | 29/41 45 | 39/39 46 | 9/3 47 | 30/2 48 | 25/20 49 | 15/6 50 | 15/23 51 | 28/40 52 | 8/7 53 | 26/23 54 | 48/10 55 | 28/28 56 | 2/13 57 | 48/14 58 | -------------------------------------------------------------------------------- /2017/input/25.txt: -------------------------------------------------------------------------------- 1 | Begin in state A. 2 | Perform a diagnostic checksum after 12208951 steps. 3 | 4 | In state A: 5 | If the current value is 0: 6 | - Write the value 1. 7 | - Move one slot to the right. 8 | - Continue with state B. 9 | If the current value is 1: 10 | - Write the value 0. 11 | - Move one slot to the left. 12 | - Continue with state E. 13 | 14 | In state B: 15 | If the current value is 0: 16 | - Write the value 1. 17 | - Move one slot to the left. 18 | - Continue with state C. 19 | If the current value is 1: 20 | - Write the value 0. 21 | - Move one slot to the right. 22 | - Continue with state A. 23 | 24 | In state C: 25 | If the current value is 0: 26 | - Write the value 1. 27 | - Move one slot to the left. 28 | - Continue with state D. 29 | If the current value is 1: 30 | - Write the value 0. 31 | - Move one slot to the right. 32 | - Continue with state C. 33 | 34 | In state D: 35 | If the current value is 0: 36 | - Write the value 1. 37 | - Move one slot to the left. 38 | - Continue with state E. 39 | If the current value is 1: 40 | - Write the value 0. 41 | - Move one slot to the left. 42 | - Continue with state F. 43 | 44 | In state E: 45 | If the current value is 0: 46 | - Write the value 1. 47 | - Move one slot to the left. 48 | - Continue with state A. 49 | If the current value is 1: 50 | - Write the value 1. 51 | - Move one slot to the left. 52 | - Continue with state C. 53 | 54 | In state F: 55 | If the current value is 0: 56 | - Write the value 1. 57 | - Move one slot to the left. 58 | - Continue with state E. 59 | If the current value is 1: 60 | - Write the value 1. 61 | - Move one slot to the right. 62 | - Continue with state A. 63 | -------------------------------------------------------------------------------- /2017/input/3.txt: -------------------------------------------------------------------------------- 1 | 325489 -------------------------------------------------------------------------------- /2017/input/6.txt: -------------------------------------------------------------------------------- 1 | 5 1 10 0 1 7 13 14 3 12 8 10 7 12 0 6 2 | -------------------------------------------------------------------------------- /2018/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2018 2 | 3 | ![hotchocolate](./img/hotchocolate.png) 4 | -------------------------------------------------------------------------------- /2018/day/1.py: -------------------------------------------------------------------------------- 1 | from itertools import cycle, accumulate 2 | data = list(map(int, open('../input/1.txt').readlines())) 3 | 4 | seen = set([0]) 5 | print(sum(data)) 6 | print(next(f for f in accumulate(cycle(data)) if f in seen or seen.add(f))) 7 | -------------------------------------------------------------------------------- /2018/day/10.py: -------------------------------------------------------------------------------- 1 | from re import findall 2 | from itertools import count 3 | 4 | data = [map(int, findall(r'-?\d+', i)) for i in open('../input/10.txt').readlines()] 5 | 6 | area = lambda x1, x2, y1, y2: (x2 - x1)*(y2 - y1) 7 | coords = lambda data, sec: [(x + vx*sec, y + vy*sec) for x, y, vx, vy in data] 8 | boundaries = lambda xs, ys: [min(xs), max(xs), min(ys), max(ys)] 9 | box_size = lambda data, sec: area(*boundaries(*zip(*coords(data, sec)))) 10 | 11 | sec = next(sec for sec in count() if box_size(data, sec) < box_size(data, sec + 1)) 12 | 13 | points = coords(data, sec) 14 | x1, x2, y1, y2 = boundaries(*zip(*points)) 15 | for j in range(y1, y2 + 1): 16 | print ''.join('#' if (i, j) in points else ' ' for i in range(x1, x2 + 1)) 17 | 18 | print sec 19 | -------------------------------------------------------------------------------- /2018/day/11.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | number = int(open('../input/11.txt').read()) 3 | 4 | grid = defaultdict(int) 5 | for y in xrange(301): 6 | for x in xrange(301): 7 | elem = (((((x + 10) * y) + number) * (x + 10))//100%10)-5 8 | grid[x, y] = grid[x-1, y] + elem + grid[x, y-1] - grid[x-1, y-1] 9 | 10 | d = {} 11 | rect = lambda x, y, n: grid[x, y] - grid[x-n, y] - grid[x, y-n] + grid[x-n, y-n] 12 | print d[max(rect(x, y, 3) for x in range(301) for y in range(301) if not d.update({rect(x, y, 3): (x-2, y-2)}))] 13 | print d[max(rect(x, y, n) for x in range(301) for y in range(301) for n in range(20) if not d.update({rect(x, y, n): (x-n+1, y-n+1, n)}))] 14 | -------------------------------------------------------------------------------- /2018/day/12.py: -------------------------------------------------------------------------------- 1 | data = (i for i in open('../input/12.txt').read().split('\n') if i) 2 | state = next(data)[15:] 3 | rules = {i[0]: i[2] for i in map(str.split, data)} 4 | psum = lambda s, off: sum(i-off*4 for i, c in enumerate(s) if c == '#') 5 | 6 | it = 1000 7 | for i in xrange(it): 8 | state = '....' + state + '....' 9 | old = state 10 | state = '..' + ''.join(rules[state[j-2:j+3]] for j in range(2, len(state) - 3)) 11 | if i == 19: 12 | print psum(state, 20) 13 | 14 | print psum(state, it) + (50000000000 - it) * (psum(state, it) - psum(old, it)) 15 | -------------------------------------------------------------------------------- /2018/day/13.py: -------------------------------------------------------------------------------- 1 | track, cars, orientation = {}, {}, '>v<^' 2 | with open('../input/13.txt') as f: 3 | for y, row in enumerate(f.read().splitlines()): 4 | for x, c in enumerate(row): 5 | track[x + y*1j] = c 6 | if c in orientation: 7 | track[x + y*1j] = '-' if c in '<>' else '|' 8 | cars[x + y*1j] = (orientation.index(c), 0) 9 | 10 | while len(cars) > 1: 11 | for xy in sorted(cars, key = lambda i: (i.imag, i.real)): 12 | if xy not in cars: 13 | continue 14 | c, (w, t) = track[xy], cars.pop(xy) # w=way, t=turn 15 | if c == '+': 16 | w = (t-1)**2*(w+t-1)%4 + (2*t-t**2)*w 17 | t = (t+1)%3 18 | if c in '/\\': 19 | w = 3-w if c == '/' else 3*w-3 20 | xy += 1j**w 21 | if xy in cars: 22 | del cars[xy] 23 | print 'crash ' + str(xy) 24 | continue 25 | cars[xy] = (w, t) 26 | 27 | print 'winner ' + str(set(cars).pop()) 28 | -------------------------------------------------------------------------------- /2018/day/14.py: -------------------------------------------------------------------------------- 1 | n = open('../input/14.txt').read().strip() 2 | x, y = 0, 1 3 | l = [3, 7] 4 | 5 | while n not in ''.join(map(str, l[-7:])): 6 | s = l[x] + l[y] 7 | l.extend(list(map(int, str(s)))) 8 | x = (x+l[x]+1) % len(l) 9 | y = (y+l[y]+1) % len(l) 10 | 11 | print ''.join(map(str, l[int(n):int(n) + 10])) 12 | print ''.join(map(str, l)).index(n) 13 | -------------------------------------------------------------------------------- /2018/day/16.py: -------------------------------------------------------------------------------- 1 | from re import findall 2 | 3 | ops = { 4 | 'addr': lambda r, A, B: r[A] + r[B], 5 | 'addi': lambda r, A, B: r[A] + B, 6 | 'mulr': lambda r, A, B: r[A] * r[B], 7 | 'muli': lambda r, A, B: r[A] * B, 8 | 'banr': lambda r, A, B: r[A] & r[B], 9 | 'bani': lambda r, A, B: r[A] & B, 10 | 'borr': lambda r, A, B: r[A] | r[B], 11 | 'bori': lambda r, A, B: r[A] | B, 12 | 'setr': lambda r, A, _: r[A], 13 | 'seti': lambda r, A, _: A, 14 | 'gtir': lambda r, A, B: int(A > r[B]), 15 | 'gtri': lambda r, A, B: int(r[A] > B), 16 | 'gtrr': lambda r, A, B: int(r[A] > r[B]), 17 | 'eqir': lambda r, A, B: int(A == r[B]), 18 | 'eqri': lambda r, A, B: int(r[A] == B), 19 | 'eqrr': lambda r, A, B: int(r[A] == r[B]), 20 | } 21 | 22 | to_ints = lambda x: (map(int, findall('-?\d+', i)) for i in x.split('\n') if i) 23 | with open('../input/16.txt') as f: 24 | test, program = map(to_ints, f.read().split('\n\n\n\n')) 25 | 26 | count, trans = 0, {} 27 | for before, (n, A, B, C), after in zip(*[test]*3): 28 | cand = set(code for code in ops if ops[code](before, A, B) == after[C]) 29 | if len(cand) >= 3: 30 | count += 1 31 | cand = cand - set(trans.values()) 32 | if len(cand) == 1: 33 | trans[n] = cand.pop() 34 | 35 | r = [0] * 4 36 | for n, A, B, C in program: 37 | r[C] = ops[trans[n]](r, A, B) 38 | 39 | print count 40 | print r[0] 41 | -------------------------------------------------------------------------------- /2018/day/17.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | clay, water, stillwater = set(), set(), set() 4 | with open('../input/17.txt') as f: 5 | for line in f: 6 | x, a, b = map(int, re.findall(r'\d+', line)) 7 | for y in range(a, b+1): 8 | clay.add((x, y) if line[0] == 'x' else (y, x)) 9 | 10 | xmin, ymin = map(min, zip(*clay)) 11 | xmax, ymax = map(max, zip(*clay)) 12 | 13 | down, leftright = {(500, 0)}, set() 14 | while down or leftright: 15 | while down: 16 | x, y = down.pop() 17 | while y <= ymax and (x, y) not in water: 18 | water.add((x,y)) 19 | if (x, y+1) in clay or (x, y+1) in stillwater: 20 | leftright.add((x, y)) 21 | break 22 | y += 1 23 | 24 | while leftright: 25 | x, y = leftright.pop() 26 | water.add((x, y)) 27 | spills = False 28 | stream = {(x, y)} 29 | for way in [-1, 1]: 30 | i, j = x+way, y 31 | while (i, j) not in clay: 32 | stream.add((i, j)) 33 | if (i, j+1) not in clay and (i, j+1) not in stillwater: 34 | down.add((i, j)) 35 | spills = True 36 | break 37 | water.add((i, j)) 38 | i += way 39 | 40 | if not spills: 41 | stillwater.update(stream) 42 | leftright.add((x, y-1)) 43 | 44 | print(len(water) - ymin) 45 | print(len(stillwater)) 46 | -------------------------------------------------------------------------------- /2018/day/18.py: -------------------------------------------------------------------------------- 1 | with open('../input/18.txt') as f: 2 | acres = {(x, y): c for y, l in enumerate(f.read().splitlines()) for x, c in enumerate(l)} 3 | 4 | vals = [] 5 | adj = [(i, j) for i in (-1, 0, 1) for j in (-1, 0, 1) if i != 0 or j != 0] 6 | for minute in xrange(1000000000): 7 | tmp = dict(acres) 8 | for y in xrange(50): 9 | for x in xrange(50): 10 | neighbors = [acres[x+i, y+j] for i, j in adj if (x+i, y+j) in acres] 11 | if acres[x, y] == '.' and neighbors.count('|') >= 3: 12 | tmp[x, y] = '|' 13 | elif acres[x, y] == '|' and neighbors.count('#') >= 3: 14 | tmp[x, y] = '#' 15 | elif acres[x, y] == '#' and not {'#', '|'} <= set(neighbors): 16 | tmp[x, y] = '.' 17 | if minute == 10: 18 | print acres.values().count('#') * acres.values().count('|') 19 | if minute >= 1000: 20 | result = acres.values().count('#') * acres.values().count('|') 21 | if result in vals: 22 | break 23 | vals.append(result) 24 | acres = dict(tmp) 25 | 26 | print vals[999999000 % len(vals)] 27 | -------------------------------------------------------------------------------- /2018/day/2.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | from operator import mul 3 | from itertools import chain 4 | 5 | data = open('../input/2.txt').read().strip().splitlines() 6 | 7 | print reduce(mul, Counter(chain(*[set(Counter(i).values()).intersection(set([2, 3])) for i in data])).values()) 8 | print next(key for i in range(len(data[0])) for key, val in Counter(k[:i] + k[i+1:] for k in data).iteritems() if val == 2) 9 | -------------------------------------------------------------------------------- /2018/day/20.py: -------------------------------------------------------------------------------- 1 | with open('../input/20.txt') as f: 2 | path = f.read()[1:-2] 3 | 4 | way = {'N': 1j, 'S': -1j, 'E': 1, 'W': -1} 5 | depth, stack = {0: 0}, [] 6 | xy = zw = 0 7 | for c in path: 8 | if c in 'NEWS': 9 | xy += way[c] 10 | if xy not in depth or depth[xy] > depth[zw]+1: 11 | depth[xy] = depth[zw]+1 12 | elif c == '(': 13 | stack.append(xy) 14 | elif c == ')': 15 | xy = stack.pop() 16 | elif c == '|': 17 | xy = stack[-1] 18 | zw = xy 19 | 20 | print(max(depth.values())) 21 | print(len([x for x in depth.values() if x >= 1000])) 22 | -------------------------------------------------------------------------------- /2018/day/22.py: -------------------------------------------------------------------------------- 1 | import re 2 | from heapq import heappush, heappop 3 | from functools import lru_cache 4 | 5 | @lru_cache(None) 6 | def gindex(xy): 7 | if xy == txy: g = 0 8 | elif xy.real == 0: g = 48271 * xy.imag 9 | elif xy.imag == 0: g = 16807 * xy.real 10 | else: g = gindex(xy-1) * gindex(xy-1j) 11 | return int(g+depth) % 20183 12 | 13 | with open('../input/22.txt') as f: 14 | depth, tx, ty = map(int, re.findall('\d+', f.read())) 15 | 16 | txy = complex(tx, ty) 17 | erosion = lambda xy: gindex(xy) % 3 18 | print(sum(erosion(x+y*1j) for x in range(tx+1) for y in range(ty+1))) 19 | 20 | # heuristic, distance, xy, gear 21 | explore = [(0, 0, 0, 0, 1), (0, 0, 7, 0, 2)] 22 | distance = {(0, 1): 0, (0, 2): 7} 23 | c = 0 # number of visited nodes 24 | 25 | while explore[0][-2:] != (txy, 1): 26 | *_, d, xy, g = heappop(explore) 27 | if distance[xy, g] < d: 28 | continue 29 | 30 | for zw in [xy+1, xy-1, xy+1j, xy-1j]: 31 | if zw.real >= 0 and zw.imag >= 0: 32 | for tg in range(3): 33 | if tg != erosion(xy) and tg != erosion(zw): 34 | td = d+1 if g == tg else d+8 35 | if distance.get((zw, tg), float('inf')) > td: 36 | distance[zw, tg] = td 37 | heappush(explore, (abs(zw-txy)+td, c:=c+1, td, zw, tg)) 38 | 39 | print(distance[txy, 1]) 40 | -------------------------------------------------------------------------------- /2018/day/23.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open('../input/23.txt') as f: 4 | nanobots = [list(map(int, re.findall(r'-?\d+', line))) for line in f] 5 | 6 | x, y, z, r = max(nanobots, key=lambda x: x[-1]) 7 | print(sum(abs(x-a) + abs(y-b) + abs(z-c) <= r 8 | for a, b, c, _ in nanobots)) 9 | 10 | from z3 import Int, If, Optimize 11 | 12 | def Abs(x): 13 | return If(x >= 0, x, -x) 14 | 15 | def Dist(x, y, z, a, b, c): 16 | return Abs(x-a) + Abs(y-b) + Abs(z-c) 17 | 18 | X = x, y, z = Int('x'), Int('y'), Int('z') 19 | cost = Int('cost') 20 | constraint = x * 0 21 | for *Y, r in nanobots: 22 | constraint += If(Dist(*X, *Y) <= r, 1, 0) 23 | 24 | opt = Optimize() 25 | opt.add(cost == constraint) 26 | h1 = opt.maximize(cost) 27 | h2 = opt.minimize(Dist(*(0, 0, 0), *X)) 28 | opt.check() 29 | print(opt.lower(h2)) 30 | -------------------------------------------------------------------------------- /2018/day/25.py: -------------------------------------------------------------------------------- 1 | with open('../input/25.txt') as f: 2 | stars = [tuple(map(int, line.split(','))) for line in f] 3 | 4 | distance = lambda x, y: sum(abs(i-j) for i, j in zip(x, y)) 5 | 6 | systems = [] 7 | for x in stars: 8 | constellation, constellations = [x], [] 9 | for system in systems: 10 | if any(distance(x, y) <= 3 for y in system): 11 | constellation.extend(system) 12 | else: 13 | constellations.append(system) 14 | systems = constellations + [constellation] 15 | 16 | print(len(systems)) 17 | -------------------------------------------------------------------------------- /2018/day/3.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import Counter 3 | 4 | data = [map(int, re.findall(r'\d+', s)) for s in open('../input/3.txt').readlines()] 5 | squares = lambda i: ((j, k) for j in range(i[1], i[1] + i[-2]) 6 | for k in range(i[2], i[2] + i[-1])) 7 | grid = Counter(x for i in data for x in squares(i)) 8 | 9 | print sum(n > 1 for n in grid.values()) 10 | print next(i[0] for i in data if all(grid[x] == 1 for x in squares(i))) 11 | -------------------------------------------------------------------------------- /2018/day/4.py: -------------------------------------------------------------------------------- 1 | from re import findall 2 | from itertools import chain 3 | from collections import defaultdict 4 | 5 | data = [map(int, findall(r'\d+', i)) for i in sorted(open('../input/4.txt').readlines())] 6 | 7 | asleep = -1 8 | guards = defaultdict(lambda: [0 for i in range(60)]) 9 | for i in data: 10 | if len(i) == 6: 11 | gid = i[-1] 12 | else: 13 | asleep *= -1 14 | for j in range(i[4], 60): 15 | guards[gid][j] += asleep 16 | 17 | p1 = max(map(sum, guards.values())) 18 | p2 = max(chain(*guards.values())) 19 | 20 | print next(gid * guards[gid].index(max(guards[gid])) for gid in guards if sum(guards[gid]) == p1) 21 | print next(gid * guards[gid].index(p2) for gid in guards if p2 in guards[gid]) 22 | -------------------------------------------------------------------------------- /2018/day/5.py: -------------------------------------------------------------------------------- 1 | purge = lambda s: reduce(lambda x, y: x[:-1] if x and ord(x[-1])^32 == ord(y) else x+y, s) 2 | data = purge(open('../input/5.txt').read().strip()) 3 | 4 | print len(data) 5 | print min(len(purge(filter(lambda x: x.upper() != c, data))) for c in map(chr, range(65, 91))) 6 | -------------------------------------------------------------------------------- /2018/day/6.py: -------------------------------------------------------------------------------- 1 | squares = lambda: ((x, y) for x in xrange(side) for y in xrange(side)) 2 | distance = lambda x, y: [abs(x-i) + abs(y-j) for i, j in data] 3 | closest = lambda x, y: next(n for n, (i, j) in enumerate(data) if not 'm' in list(locals().keys()) and locals().update({'m': min(distance(x, y))}) or abs(x-i) + abs(y-j) == locals()['m']) 4 | 5 | data = [map(int, i.split(', ')) for i in open('../input/6.txt').readlines()] 6 | 7 | side = max(max(zip(*data)[0]), max(zip(*data)[1])) 8 | eqidistant = set((x, y) for x, y in squares() if distance(x, y).count(min(distance(x, y))) > 1) 9 | grid = {(x, y): closest(x, y) if (x, y) not in eqidistant else -1 for x, y in squares()} 10 | inf = set(grid[x, y] for edge in xrange(side) for x, y in [(edge, side-1), (edge, 0), (side-1, edge), (0, edge)]) 11 | 12 | print max(grid.values().count(n) for n in xrange(len(data)) if n not in inf) 13 | print sum(sum(distance(x, y)) < 10000 for x, y in squares()) 14 | -------------------------------------------------------------------------------- /2018/day/7.py: -------------------------------------------------------------------------------- 1 | from networkx import DiGraph, lexicographical_topological_sort as lt_sort 2 | 3 | data = [(i[1], i[-3]) for i in map(str.split, open('../input/7.txt').readlines())] 4 | print(''.join(lt_sort(DiGraph(data)))) 5 | 6 | step_reqs = {i: set() for i in (j for i in data for j in i)} 7 | for i in data: 8 | step_reqs[i[1]].add(i[0]) 9 | 10 | cnt, d = 0, {} 11 | while step_reqs: 12 | [0 for i in list(step_reqs.keys()) if not step_reqs[i] and (d.update({i: cnt + ord(i) - 4}) or step_reqs.pop(i))] 13 | cnt += 1 14 | [0 for c in d for c2 in step_reqs if d[c] == cnt and c in step_reqs[c2] and step_reqs[c2].remove(c)] 15 | 16 | # prints shortest path i.e. as if there were infinite number of workers rather than 5 as in the task 17 | print max(d.values()) 18 | -------------------------------------------------------------------------------- /2018/day/8.py: -------------------------------------------------------------------------------- 1 | def solve(child, meta): 2 | if child == 0: 3 | return [sum(next(data) for _ in range(meta))]*2 4 | children = {} 5 | total = value = 0 6 | for i in range(1, child+1): 7 | _total, _value = solve(next(data), next(data)) 8 | total += _total 9 | children[i] = _value 10 | for _ in range(meta): 11 | _next = next(data) 12 | total += _next 13 | value += children.get(_next, 0) 14 | return total, value 15 | 16 | data = iter(map(int, open('../input/8.txt').read().split())) 17 | 18 | print(solve(next(data), next(data))) 19 | -------------------------------------------------------------------------------- /2018/day/9.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def solve(players, last): 4 | circle = deque([0]) 5 | scores = [0]*players 6 | for turn in xrange(1, last+1): 7 | player = (turn-1)%players 8 | if not turn % 23: 9 | circle.rotate(7) 10 | scores[player] += turn + circle.popleft() 11 | else: 12 | circle.rotate(-2) 13 | circle.appendleft(turn) 14 | print max(scores) 15 | 16 | players, last = (int(i) for i in open('../input/9.txt').read().split() if i.isdigit()) 17 | solve(players, last) 18 | solve(players, last*100) 19 | -------------------------------------------------------------------------------- /2018/img/hotchocolate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2018/img/hotchocolate.png -------------------------------------------------------------------------------- /2018/input/11.txt: -------------------------------------------------------------------------------- 1 | 7857 2 | -------------------------------------------------------------------------------- /2018/input/12.txt: -------------------------------------------------------------------------------- 1 | initial state: ##...#......##......#.####.##.#..#..####.#.######.##..#.####...##....#.#.####.####.#..#.######.##... 2 | 3 | #.... => . 4 | #..## => # 5 | ....# => . 6 | ...#. => . 7 | ...## => # 8 | #.#.# => . 9 | .#... => # 10 | ##.#. => . 11 | ..#.# => . 12 | .##.# => # 13 | ###.# => # 14 | .#.## => . 15 | ..... => . 16 | ##### => # 17 | ###.. => . 18 | ##..# => # 19 | #.### => # 20 | #.#.. => . 21 | ..### => . 22 | ..#.. => . 23 | .#..# => # 24 | .##.. => # 25 | ##... => # 26 | .#.#. => # 27 | .###. => # 28 | #..#. => . 29 | ####. => . 30 | .#### => # 31 | #.##. => # 32 | ##.## => . 33 | ..##. => . 34 | #...# => # 35 | -------------------------------------------------------------------------------- /2018/input/14.txt: -------------------------------------------------------------------------------- 1 | 633601 2 | -------------------------------------------------------------------------------- /2018/input/15.txt: -------------------------------------------------------------------------------- 1 | ################################ 2 | ##########################..#### 3 | #########################...#### 4 | #########################..##### 5 | ########################G..##### 6 | #####################.#.....##.# 7 | #####################..........# 8 | ##############.#####...........# 9 | ########G...G#.####............# 10 | #######......G....#.....#......# 11 | #######...G....GG.#............# 12 | #######G.G.............####....# 13 | #######.#.....#####....E.....### 14 | #######......#######.G.......### 15 | #..####..G..#########.###..##### 16 | #........G..#########.########## 17 | #..#..#G....#########.########## 18 | #.###...E...#########.########## 19 | #####...G.G.#########.########## 20 | ########G....#######..########## 21 | ####..........#####...########## 22 | ####......E........G..########## 23 | #.G..................########### 24 | #G...................########### 25 | ###.....##E.......E..########### 26 | ###....#............############ 27 | ###.................############ 28 | ##G.....#.............########## 29 | ###########...#E..##..########## 30 | ###########.E...###.E.EE.####### 31 | ###########......#.......####### 32 | ################################ 33 | -------------------------------------------------------------------------------- /2018/input/19.txt: -------------------------------------------------------------------------------- 1 | #ip 3 2 | addi 3 16 3 3 | seti 1 9 5 4 | seti 1 1 4 5 | mulr 5 4 2 6 | eqrr 2 1 2 7 | addr 2 3 3 8 | addi 3 1 3 9 | addr 5 0 0 10 | addi 4 1 4 11 | gtrr 4 1 2 12 | addr 3 2 3 13 | seti 2 3 3 14 | addi 5 1 5 15 | gtrr 5 1 2 16 | addr 2 3 3 17 | seti 1 4 3 18 | mulr 3 3 3 19 | addi 1 2 1 20 | mulr 1 1 1 21 | mulr 3 1 1 22 | muli 1 11 1 23 | addi 2 2 2 24 | mulr 2 3 2 25 | addi 2 20 2 26 | addr 1 2 1 27 | addr 3 0 3 28 | seti 0 4 3 29 | setr 3 9 2 30 | mulr 2 3 2 31 | addr 3 2 2 32 | mulr 3 2 2 33 | muli 2 14 2 34 | mulr 2 3 2 35 | addr 1 2 1 36 | seti 0 6 0 37 | seti 0 0 3 38 | -------------------------------------------------------------------------------- /2018/input/21.txt: -------------------------------------------------------------------------------- 1 | #ip 5 2 | seti 123 0 2 3 | bani 2 456 2 4 | eqri 2 72 2 5 | addr 2 5 5 6 | seti 0 0 5 7 | seti 0 9 2 8 | bori 2 65536 1 9 | seti 1250634 6 2 10 | bani 1 255 4 11 | addr 2 4 2 12 | bani 2 16777215 2 13 | muli 2 65899 2 14 | bani 2 16777215 2 15 | gtir 256 1 4 16 | addr 4 5 5 17 | addi 5 1 5 18 | seti 27 2 5 19 | seti 0 5 4 20 | addi 4 1 3 21 | muli 3 256 3 22 | gtrr 3 1 3 23 | addr 3 5 5 24 | addi 5 1 5 25 | seti 25 5 5 26 | addi 4 1 4 27 | seti 17 2 5 28 | setr 4 8 1 29 | seti 7 6 5 30 | eqrr 2 0 4 31 | addr 4 5 5 32 | seti 5 7 5 33 | -------------------------------------------------------------------------------- /2018/input/22.txt: -------------------------------------------------------------------------------- 1 | depth: 8112 2 | target: 13,743 3 | -------------------------------------------------------------------------------- /2018/input/6.txt: -------------------------------------------------------------------------------- 1 | 108, 324 2 | 46, 91 3 | 356, 216 4 | 209, 169 5 | 170, 331 6 | 332, 215 7 | 217, 104 8 | 75, 153 9 | 110, 207 10 | 185, 102 11 | 61, 273 12 | 233, 301 13 | 278, 151 14 | 333, 349 15 | 236, 249 16 | 93, 155 17 | 186, 321 18 | 203, 138 19 | 103, 292 20 | 47, 178 21 | 178, 212 22 | 253, 174 23 | 348, 272 24 | 83, 65 25 | 264, 227 26 | 239, 52 27 | 243, 61 28 | 290, 325 29 | 135, 96 30 | 165, 339 31 | 236, 132 32 | 84, 185 33 | 94, 248 34 | 164, 82 35 | 325, 202 36 | 345, 323 37 | 45, 42 38 | 292, 214 39 | 349, 148 40 | 80, 180 41 | 314, 335 42 | 210, 264 43 | 302, 108 44 | 235, 273 45 | 253, 170 46 | 150, 303 47 | 249, 279 48 | 255, 159 49 | 273, 356 50 | 275, 244 51 | -------------------------------------------------------------------------------- /2018/input/9.txt: -------------------------------------------------------------------------------- 1 | 418 players; last marble is worth 71339 points 2 | -------------------------------------------------------------------------------- /2019/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2019 2 | 3 | ![universe](./img/universe.png) 4 | -------------------------------------------------------------------------------- /2019/day/1.py: -------------------------------------------------------------------------------- 1 | with open('../input/1.txt') as f: 2 | data = list(map(int, f.read().split('\n')[:-1])) 3 | 4 | fuel = lambda x: fuel(x//3-2) + x if x > 0 else 0 5 | print(sum(x//3-2 for x in data)) 6 | print(sum(fuel(x//3-2) for x in data)) 7 | -------------------------------------------------------------------------------- /2019/day/10.py: -------------------------------------------------------------------------------- 1 | from math import atan2, pi 2 | 3 | with open('../input/10.txt') as f: 4 | asteroids = set((x, y) for y, l in enumerate(f) 5 | for x, c in enumerate(l.strip()) if c == '#') 6 | 7 | def angle(x, y, z, w): 8 | return 2*pi - atan2(z-x, w-y) 9 | 10 | def dist(x, y, z, w): 11 | return abs(z-x) + abs(w-y) 12 | 13 | n, xy = max((len(set(angle(*xy, *zw) for zw in asteroids if xy != zw)), xy) 14 | for xy in asteroids) 15 | 16 | a = list(sorted(set(angle(*xy, *zw) for zw in asteroids)))[199] 17 | x, y = min(filter(lambda zw: angle(*xy, *zw) == a and xy != zw, asteroids), 18 | key=lambda zw: dist(*xy, *zw)) 19 | 20 | print(n) 21 | print(x*100 + y) 22 | -------------------------------------------------------------------------------- /2019/day/11.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | intcode = __import__('9').intcode 3 | 4 | with open('../input/11.txt') as f: 5 | tape = list(map(int, f.read().split(','))) 6 | 7 | xy, d = 0j, -1j 8 | colors = defaultdict(int) 9 | colors[0] = 1 # comment for part 1 10 | 11 | robot = intcode(tape, (colors[xy] for _ in iter(int, 1))) 12 | for color, turn in iter(lambda: [next(robot), next(robot)], 1): 13 | colors[xy] = color 14 | d /= 1j**(-1)**turn 15 | xy += d 16 | 17 | # print(len(colors)) # uncomment for part 1 18 | for y in range(6): 19 | print(''.join('#' if colors[x+y*1j] else ' ' for x in range(40))) 20 | -------------------------------------------------------------------------------- /2019/day/12.py: -------------------------------------------------------------------------------- 1 | from math import gcd 2 | from re import findall 3 | from itertools import combinations, count 4 | 5 | 6 | def lcm(x, y): 7 | return abs(x*y) // gcd(x, y) 8 | 9 | 10 | with open('../input/12.txt') as f: 11 | moons = [[list(map(int, findall(r'-?\d+', line))), [0]*3] for line in f] 12 | 13 | start = list(zip(*list(m for moon in moons for m in moon))) 14 | energy = [[[0]*3, [0]*3] for _ in moons] 15 | period = 1 16 | for i in range(3): 17 | for t in count(): 18 | for (s1, v1), (s2, v2) in combinations(moons, 2): 19 | v1[i] += (s1[i] < s2[i]) - (s1[i] > s2[i]) 20 | v2[i] += (s2[i] < s1[i]) - (s2[i] > s1[i]) 21 | 22 | for j, (s, v) in enumerate(moons): 23 | s[i] += v[i] 24 | if t == 999: 25 | energy[j][0][i] = abs(s[i]) 26 | energy[j][1][i] = abs(v[i]) 27 | 28 | if start[i] == list(zip(*list(m for moon in moons for m in moon)))[i]: 29 | period = lcm(period, t+1) 30 | break 31 | 32 | print(sum(sum(moon[0]) * sum(moon[1]) for moon in energy)) 33 | print(period) 34 | -------------------------------------------------------------------------------- /2019/day/13.py: -------------------------------------------------------------------------------- 1 | intcode = __import__('9').intcode 2 | 3 | with open('../input/13.txt') as f: 4 | tape = list(map(int, f.read().split(','))) 5 | 6 | grid = {} 7 | tape[0] = 2 8 | ball = player = None 9 | player_input = (-1 if ball < player else ball > player for _ in iter(int, 1)) 10 | game = intcode(tape, player_input) 11 | 12 | for x, y, t in iter(lambda: [next(game) for _ in range(3)], 1): 13 | if x == -1 and y == 0 and t == 0: 14 | print(sum(grid[i] == 2 for i in grid)) 15 | 16 | if t <= 4: 17 | grid[x, y] = t 18 | if t == 3: 19 | player = x 20 | elif t == 4: 21 | ball = x 22 | 23 | print(t) 24 | -------------------------------------------------------------------------------- /2019/day/14.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from math import ceil 3 | from re import findall 4 | 5 | 6 | def ore_needed_for_n_fuel(n): 7 | ore = 0 8 | orders = defaultdict(int, {'FUEL': n}) 9 | waste = defaultdict(int) 10 | while orders: 11 | chemical, amount_needed = orders.popitem() 12 | amount_produced, reactants = reactions[chemical] 13 | 14 | if waste[chemical] >= amount_needed: 15 | waste[chemical] -= amount_needed 16 | else: 17 | amount_needed = amount_needed - waste[chemical] 18 | waste[chemical] = 0 19 | reactions_needed = ceil(amount_needed/amount_produced) 20 | waste[chemical] += reactions_needed*amount_produced - amount_needed 21 | 22 | for reactant in reactants: 23 | if reactant == 'ORE': 24 | ore += reactions_needed * reactants[reactant] 25 | else: 26 | orders[reactant] += reactions_needed * reactants[reactant] 27 | return ore 28 | 29 | 30 | reactions = dict() 31 | with open('../input/14.txt') as f: 32 | for line in f.readlines(): 33 | *reactants, product = [(name, int(amount)) for _, amount, name in 34 | findall(r'((\d+) (\w+)[, =>]?)+', line)] 35 | reactions[product[0]] = (product[1], dict(reactants)) 36 | 37 | fuel = ore_needed_for_n_fuel(1) # part2 do manual golden search over digits 38 | print(fuel) 39 | -------------------------------------------------------------------------------- /2019/day/15.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | intcode = __import__('9').intcode 3 | 4 | with open('../input/15.txt') as f: 5 | tape = list(map(int, f.read().split(','))) 6 | 7 | i = None 8 | xy = 0 9 | reverse = [2, 1, 4, 3] 10 | moves = list(range(1, 5)) 11 | directions = [1j, -1j, -1, 1] 12 | grid = defaultdict(lambda: 3) 13 | robot = intcode(tape, (i := moves.pop() for _ in iter(int, 1))) 14 | 15 | for block in robot: 16 | zw = xy + directions[i-1] 17 | if block: 18 | xy = zw 19 | if grid[xy] == 4: 20 | moves.append(reverse[i-1]) 21 | 22 | for j, d in enumerate(directions): 23 | if grid[xy+d] == 3: 24 | moves.append(j+1) 25 | grid[xy+d] = 4 26 | 27 | grid[zw] = block 28 | if not moves: 29 | break 30 | 31 | # for y in range(21, -20, -1): 32 | # print(''.join('#.$ ?'[grid[x+y*1j]] if x+y*1j != xy else 'D' 33 | # for x in range(-21, 22))) 34 | 35 | xy = 0 36 | # xy = next(xy for xy in grid if grid[xy] == 2) # uncomment for part2 37 | visit = [xy] 38 | distance = defaultdict(int) 39 | while visit: 40 | xy = visit.pop() 41 | if grid[xy] == 2 and distance[xy] > 2: 42 | break 43 | 44 | for d in directions: 45 | if grid[xy+d] and not distance[xy+d]: 46 | visit.append(xy+d) 47 | distance[xy+d] = distance[xy] + 1 48 | 49 | print(max(distance.values())) 50 | -------------------------------------------------------------------------------- /2019/day/16.py: -------------------------------------------------------------------------------- 1 | from itertools import accumulate 2 | 3 | with open('../input/16.txt') as f: 4 | sequence_ = sequence = f.read()[:-1] 5 | 6 | offset = int(sequence[:7]) 7 | 8 | base_pattern = [0, 1, 0, -1] 9 | sequence = list(map(int, sequence)) 10 | for phase in range(100): 11 | new_sequence = [0] * len(sequence) 12 | for i in range(len(sequence)): 13 | pattern = (element for _ in iter(int, None) 14 | for element in base_pattern for _ in range(i + 1)) 15 | next(pattern) 16 | new_sequence[i] = abs(sum(j*k for j, k in zip(sequence, pattern))) % 10 17 | sequence = new_sequence 18 | 19 | print(*sequence[:8], sep='') 20 | 21 | sequence = list(map(int, sequence_*10000))[offset:][::-1] 22 | 23 | for _ in range(100): 24 | sequence = list(accumulate(sequence, lambda x, y: (x + y) % 10)) 25 | 26 | print(*sequence[::-1][:8], sep='') 27 | -------------------------------------------------------------------------------- /2019/day/17.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | intcode = __import__('9').intcode 3 | 4 | with open('../input/17.txt') as f: 5 | tape = list(map(int, f.read().split(','))) 6 | 7 | direction = {'^': -1j, 'v': 1j, '>': 1, '<': -1} 8 | grid = defaultdict(lambda: '.') 9 | zw = xy = 0j 10 | d = None 11 | for c in map(chr, intcode(tape, None)): 12 | if c == '\n': 13 | zw = (zw.imag+1)*1j 14 | continue 15 | elif c in direction: 16 | d = direction[c] 17 | xy = zw 18 | grid[zw] = c 19 | zw += 1 20 | 21 | alignment = 0 22 | for zw in dict(grid): 23 | if grid[zw] == '#' and all(grid[zw+d] == '#' for d in direction.values()): 24 | alignment += zw.real * zw.imag 25 | 26 | print(int(alignment)) 27 | 28 | path = [] 29 | forward = 0 30 | while '#' in {grid[xy+d], grid[xy+d*1j], grid[xy+d/1j]}: 31 | if grid[xy+d] == '#': 32 | forward += 1 33 | xy += d 34 | continue 35 | 36 | if forward: 37 | path.append(forward) 38 | forward = 0 39 | 40 | if grid[xy+d*1j] == '#': 41 | path.append('R') 42 | d *= 1j 43 | 44 | elif grid[xy+d/1j] == '#': 45 | path.append('L') 46 | d /= 1j 47 | 48 | path.append(forward) 49 | 50 | # print(path) # manually get: A, B, C ain't that hard 51 | path = list(map(str, path)) 52 | 53 | 54 | def robot_input(*patterns): 55 | for pattern in patterns: 56 | for c in pattern: 57 | yield ord(c) 58 | yield ord('n') 59 | yield ord('\n') 60 | 61 | 62 | main = 'A,C,A,C,B,B,C,A,C,B\n' 63 | A = 'L,8,R,12,R,12,R,10\n' 64 | B = 'L,10,R,10,L,6\n' 65 | C = 'R,10,R,12,R,10\n' 66 | 67 | tape[0] = 2 68 | for output in intcode(tape, robot_input(main, A, B, C)): 69 | if output > 50000: 70 | print(output) 71 | -------------------------------------------------------------------------------- /2019/day/19.py: -------------------------------------------------------------------------------- 1 | intcode = __import__('9').intcode 2 | 3 | with open('../input/19.txt') as f: 4 | tape = list(map(int, f.read().split(','))) 5 | 6 | ray = lambda x, y: next(intcode(tape, iter([x, y]))) 7 | 8 | y, start = -1, 0 9 | rows = {y: [start, start]} 10 | while y <= 100 or rows[y-99][1] - start < 100: 11 | x = start 12 | y += 1 13 | if y == 50: 14 | x1, x2 = list(map(sum, zip(*rows.values()))) 15 | print(x2 - x1) 16 | 17 | for _ in range(10): # taking care of empty rows 18 | if ray(x, y): 19 | break 20 | x += 1 21 | else: 22 | rows[y] = rows[y-1][:] 23 | if rows[y-1][1] > rows[y-1][0]: # if the row above is not empty 24 | rows[y][1] -= 1 25 | continue 26 | 27 | start = x 28 | x = max(start, rows[y-1][1]) 29 | while ray(x, y): 30 | x += 1 31 | 32 | rows[y] = [start, x] 33 | 34 | print(start*10000 + y - 99) 35 | -------------------------------------------------------------------------------- /2019/day/2.py: -------------------------------------------------------------------------------- 1 | with open('../input/2.txt') as f: 2 | data = list(map(int, f.read().split(','))) 3 | 4 | def run(l, i, j): 5 | l[1], l[2] = i, j 6 | for i in range(0, len(l), 4): 7 | if l[i] == 99: 8 | return l[0] 9 | a, b = l[l[i+1]], l[l[i+2]] 10 | l[l[i+3]] = a + b if l[i] == 1 else a * b 11 | 12 | print(run(data[:], 12, 2)) 13 | print(next(100*i+j for i in range(100) 14 | for j in range(100) if run(data[:], i, j) == 19690720)) 15 | -------------------------------------------------------------------------------- /2019/day/21.py: -------------------------------------------------------------------------------- 1 | intcode = __import__('9').intcode 2 | 3 | with open('../input/21.txt') as f: 4 | tape = list(map(int, f.read().split(','))) 5 | 6 | part1 = """ 7 | OR A J 8 | AND B J 9 | AND C J 10 | NOT J J 11 | AND D J 12 | WALK 13 | """ # ~(ABC)D 14 | 15 | part2 = """ 16 | OR A J 17 | AND B J 18 | AND C J 19 | NOT J J 20 | OR E T 21 | OR H T 22 | AND T J 23 | AND D J 24 | RUN 25 | """ 26 | springscript = (ord(c) for c in part2[1:]) 27 | for output in intcode(tape, springscript): 28 | if output <= 1114111: 29 | print(chr(output), end='') 30 | 31 | print(output) 32 | -------------------------------------------------------------------------------- /2019/day/22.py: -------------------------------------------------------------------------------- 1 | def get_coefficients(length): 2 | a, b = 1, 0 3 | with open('../input/22.txt') as f: 4 | for cmd, *_, n in map(str.split, f): 5 | if cmd == 'deal' and n.startswith('stack'): 6 | b = (length - 1 - b) % length 7 | 8 | elif cmd == 'cut': 9 | b = (b - int(n)) % length 10 | 11 | else: 12 | a = a*int(n) % length 13 | b = b*int(n) % length 14 | return a, b 15 | 16 | 17 | card = 2019 18 | length = 10007 19 | a, b = get_coefficients(length) 20 | print(position := (a * card + b) % length) 21 | 22 | position = 2020 23 | length = 119315717514047 24 | iterations = 101741582076661 25 | a, b = get_coefficients(length) 26 | 27 | inv_a = pow(a, length - 2, length) 28 | inv_a_to_k = pow(inv_a, iterations, length) 29 | coef = ((inv_a_to_k - 1) * pow(inv_a - 1, length - 2, length) - 1) % length 30 | print(((position - b) * inv_a_to_k - b * coef) % length) 31 | -------------------------------------------------------------------------------- /2019/day/23.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from queue import Queue 3 | from time import sleep 4 | intcode = __import__('9').intcode 5 | 6 | def reciever(i): 7 | yield i 8 | while True: 9 | if queue[i].empty(): 10 | yield -1 11 | else: 12 | x, y = queue[i].get() 13 | yield x 14 | yield y 15 | 16 | def run(computer, i): 17 | global NAT 18 | for destination in computer: 19 | package = (x := next(computer), y := next(computer)) 20 | if destination == 255: 21 | if not NAT: 22 | print(y) # part 1 23 | # print(f'{i} sending {package} to NAT') 24 | NAT = package 25 | continue 26 | queue[destination].put(package) 27 | # print(f'{i} sending {package} to {destination}') 28 | 29 | with open('../input/23.txt') as f: 30 | tape = list(map(int, f.read().split(','))) 31 | 32 | queue = [Queue() for _ in range(50)] 33 | last_y = NAT = None 34 | for i in range(50): 35 | computer = intcode(tape, reciever(i)) 36 | t = Thread(target=run, args=(computer, i), daemon=True) 37 | t.start() 38 | 39 | while True: 40 | if all(q.empty() for q in queue): 41 | sleep(2) # tries to ensure that all threads are waiting for input 42 | if any(not q.empty() for q in queue): 43 | continue 44 | if last_y == NAT[1]: 45 | print(last_y) # part 2 46 | break 47 | queue[0].put(NAT) 48 | last_y = NAT[1] 49 | -------------------------------------------------------------------------------- /2019/day/25.py: -------------------------------------------------------------------------------- 1 | intcode = __import__('9').intcode 2 | 3 | with open('../input/25.txt') as f: 4 | code = list(map(int, f.read().split(','))) 5 | 6 | game_input = (ord(c) for _ in iter(int, 1) for c in (input()+'\n')) 7 | for c in map(chr, intcode(code, game_input)): 8 | print(c, end='') 9 | -------------------------------------------------------------------------------- /2019/day/3.py: -------------------------------------------------------------------------------- 1 | with open('../input/3.txt') as f: 2 | data = [s.split(',') for s in f.read().split('\n')[:-1]] 3 | 4 | wire = [dict(), dict()] 5 | for i, w in enumerate(data): 6 | x = y = z = 0 7 | for j in w: 8 | for _ in range(int(j[1:])): 9 | if j[0] in 'LR': 10 | x += 1 if j[0] == 'R' else -1 11 | else: 12 | y += 1 if j[0] == 'U' else -1 13 | wire[i][(x, y)] = z 14 | z += 1 15 | 16 | cross = set(wire[0]).intersection(set(wire[1])) 17 | print(sorted(abs(x[0]) + abs(x[1]) for x in cross)[0]) 18 | print(sorted(wire[0][x]+wire[1][x] for x in cross)[0]+2) 19 | -------------------------------------------------------------------------------- /2019/day/4.py: -------------------------------------------------------------------------------- 1 | with open('../input/4.txt') as f: 2 | x, y = map(int, f.read().split('-')) 3 | 4 | counter = 0 5 | for i in range(x, y+1): 6 | standalone = False 7 | password = str(i) 8 | digit = 0 9 | for j in range(len(password)-1): 10 | if password[j] > password[j+1]: 11 | break 12 | 13 | if password[j] == password[j+1]: 14 | digit += 1 15 | else: 16 | if digit == 1: 17 | standalone = True 18 | digit = 0 19 | 20 | # if digit: digit = 1 # uncomment for part1 21 | else: 22 | if standalone or digit == 1: 23 | counter += 1 24 | 25 | print(counter) 26 | -------------------------------------------------------------------------------- /2019/day/5.py: -------------------------------------------------------------------------------- 1 | with open('../input/5.txt') as f: 2 | l = list(map(int, f.read().split(','))) 3 | 4 | i, jump = 0, [None, 4, 4, 2, 2, 0, 0, 4, 4, 2] 5 | while True: 6 | opcode, mode = l[i] % 100, str(l[i]//100).zfill(2)[::-1] 7 | arg = lambda x: l[l[i+x]] if mode[x-1] == '0' else l[i+x] 8 | 9 | if opcode == 99: # halt 10 | break 11 | 12 | elif opcode == 1: # add 13 | l[l[i+3]] = arg(1) + arg(2) 14 | 15 | elif opcode == 2: # multiply 16 | l[l[i+3]] = arg(1) * arg(2) 17 | 18 | elif opcode == 3: # input 19 | l[l[i+1]] = int(input('input a number: ')) 20 | 21 | elif opcode == 4: # output 22 | print(f'output: {arg(1)}') 23 | 24 | elif opcode == 5: # jump if true 25 | i = arg(2) if arg(1) else i+3 26 | 27 | elif opcode == 6: # jump if false 28 | i = arg(2) if not arg(1) else i+3 29 | 30 | elif opcode == 7: # less than 31 | l[l[i+3]] = arg(1) < arg(2) 32 | 33 | elif opcode == 8: # equals 34 | l[l[i+3]] = arg(1) == arg(2) 35 | 36 | else: # error 37 | raise Exception(f'invalid opcode {opcode}') 38 | 39 | i += jump[opcode] 40 | -------------------------------------------------------------------------------- /2019/day/6.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | stars = defaultdict(set) 4 | with open('../input/6.txt') as f: 5 | for line in f: 6 | parent, child = line[:-1].split(')') 7 | stars[parent].add(child) 8 | 9 | tree = dict() 10 | nodes = [['COM', tree]] 11 | while nodes: 12 | name, root = nodes.pop() 13 | for star in stars[name]: 14 | root[star] = dict() 15 | nodes.append([star, root[star]]) 16 | 17 | nodes.append(tree) 18 | count, level = 0, 1 19 | santa = you = parent = 0 20 | while any(nodes): 21 | for node in nodes: 22 | for child in node: 23 | count += level 24 | if child == 'SAN': 25 | santa = level 26 | 27 | if child == 'YOU': 28 | you = level 29 | 30 | subtree = str(node[child]) 31 | if 'SAN' in subtree and 'YOU' in subtree: 32 | parent = level 33 | 34 | nodes = [node[child] for node in nodes for child in node] 35 | level += 1 36 | 37 | print(count) 38 | print(santa + you - 2*parent - 2) 39 | -------------------------------------------------------------------------------- /2019/day/7.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | from more_itertools import roundrobin 3 | from collections import deque 4 | intcode = __import__('9').intcode 5 | 6 | with open('../input/7.txt') as f: 7 | tape = list(map(int, f.read().split(','))) 8 | 9 | best = 0 10 | # for permutation in permutations(range(5)): # uncomment for part1 11 | for permutation in permutations(range(5, 10)): # comment for part1 12 | queue = list(map(lambda p: deque([p]), permutation)) 13 | fromqueue = lambda i: (queue[i].popleft() for _ in iter(int, 1)) 14 | amplifiers = [intcode(tape, fromqueue(i)) for i in range(5)] 15 | queue[0].append(0) 16 | for i, output in enumerate(roundrobin(*amplifiers)): 17 | queue[(i+1)%5].append(output) 18 | 19 | best = max(best, queue[0].pop()) 20 | 21 | print(best) 22 | -------------------------------------------------------------------------------- /2019/day/8.py: -------------------------------------------------------------------------------- 1 | def split_every_n(l, n): 2 | return [l[i:i+n] for i in range(0, len(l), n)] 3 | 4 | with open('../input/8.txt') as f: 5 | images = split_every_n(list(map(int, f.read()[:-1])), 25*6) 6 | 7 | image = min(images, key=lambda image: image.count(0)) 8 | print(image.count(1) * image.count(2)) 9 | 10 | image = ''.join('#' if next(pixel for pixel in layer if pixel != 2) else ' ' 11 | for layer in zip(*images)) 12 | 13 | print('\n'.join(split_every_n(image, 25))) 14 | -------------------------------------------------------------------------------- /2019/day/9.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from typing import List, Iterator 3 | 4 | def intcode(tape: List[int], int_input: Iterator[int]) -> Iterator[int]: 5 | tape = defaultdict(int, dict(enumerate(tape))) 6 | i = rb = 0 7 | jump = [4, 4, 2, 2, 0, 0, 4, 4, 2] 8 | modes = lambda x, m: [tape[x+i], x+i, rb+tape[x+i]][m] 9 | while True: 10 | opcode = tape[i] % 100 11 | mode = str(tape[i]//100).zfill(3)[::-1] 12 | arg = lambda x: tape[pos(x)] 13 | pos = lambda x: modes(x, int(mode[x-1])) 14 | 15 | if opcode == 99: break 16 | elif opcode == 1: tape[pos(3)] = arg(1) + arg(2) 17 | elif opcode == 2: tape[pos(3)] = arg(1) * arg(2) 18 | elif opcode == 3: tape[pos(1)] = next(int_input) 19 | elif opcode == 4: yield arg(1) 20 | elif opcode == 5: i = arg(2) if arg(1) else i+3 21 | elif opcode == 6: i = arg(2) if not arg(1) else i+3 22 | elif opcode == 7: tape[pos(3)] = arg(1) < arg(2) 23 | elif opcode == 8: tape[pos(3)] = arg(1) == arg(2) 24 | elif opcode == 9: rb += arg(1) 25 | else: raise Exception(f'invalid opcode {opcode}') 26 | 27 | i += jump[opcode-1] 28 | 29 | if __name__ == '__main__': 30 | with open('../input/9.txt') as f: 31 | tape = list(map(int, f.read().split(','))) 32 | 33 | for o in intcode(tape, (int(input('input: ')) for _ in iter(int, 1))): 34 | print(f'output: {o}') 35 | -------------------------------------------------------------------------------- /2019/img/universe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2019/img/universe.png -------------------------------------------------------------------------------- /2019/input/1.txt: -------------------------------------------------------------------------------- 1 | 132791 2 | 78272 3 | 114679 4 | 60602 5 | 59038 6 | 69747 7 | 61672 8 | 147972 9 | 92618 10 | 70186 11 | 125826 12 | 61803 13 | 78112 14 | 124864 15 | 58441 16 | 113062 17 | 105389 18 | 125983 19 | 90716 20 | 75544 21 | 148451 22 | 73739 23 | 127762 24 | 146660 25 | 128747 26 | 148129 27 | 138635 28 | 80095 29 | 60241 30 | 145455 31 | 98730 32 | 59139 33 | 146828 34 | 113550 35 | 91682 36 | 107415 37 | 129207 38 | 147635 39 | 104583 40 | 102245 41 | 73446 42 | 148657 43 | 96364 44 | 52033 45 | 69964 46 | 63609 47 | 98207 48 | 73401 49 | 65511 50 | 115034 51 | 126179 52 | 96664 53 | 85394 54 | 128472 55 | 79017 56 | 93222 57 | 55267 58 | 102446 59 | 133150 60 | 148985 61 | 95325 62 | 57713 63 | 77370 64 | 60879 65 | 111977 66 | 99362 67 | 91581 68 | 55201 69 | 137670 70 | 127159 71 | 128324 72 | 77217 73 | 86378 74 | 112847 75 | 108265 76 | 80355 77 | 75650 78 | 106222 79 | 67793 80 | 113891 81 | 74508 82 | 139463 83 | 69972 84 | 122753 85 | 135854 86 | 127770 87 | 101085 88 | 98304 89 | 61451 90 | 146719 91 | 61225 92 | 60468 93 | 83613 94 | 137436 95 | 126303 96 | 78759 97 | 70081 98 | 110671 99 | 113234 100 | 111563 101 | -------------------------------------------------------------------------------- /2019/input/10.txt: -------------------------------------------------------------------------------- 1 | #..#.#.#.######..#.#...## 2 | ##.#..#.#..##.#..######.# 3 | .#.##.#..##..#.#.####.#.. 4 | .#..##.#.#..#.#...#...#.# 5 | #...###.##.##..##...#..#. 6 | ##..#.#.#.###...#.##..#.# 7 | ###.###.#.##.##....#####. 8 | .#####.#.#...#..#####..#. 9 | .#.##...#.#...#####.##... 10 | ######.#..##.#..#.#.#.... 11 | ###.##.#######....##.#..# 12 | .####.##..#.##.#.#.##...# 13 | ##...##.######..##..#.### 14 | ...###...#..#...#.###..#. 15 | .#####...##..#..#####.### 16 | .#####..#.#######.###.##. 17 | #...###.####.##.##.#.##.# 18 | .#.#.#.#.#.##.#..#.#..### 19 | ##.#.####.###....###..##. 20 | #..##.#....#..#..#.#..#.# 21 | ##..#..#...#..##..####..# 22 | ....#.....##..#.##.#...## 23 | .##..#.#..##..##.#..##..# 24 | .##..#####....#####.#.#.# 25 | #..#..#..##...#..#.#.#.## 26 | -------------------------------------------------------------------------------- /2019/input/12.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /2019/input/14.txt: -------------------------------------------------------------------------------- 1 | 5 HLJD, 1 QHSZD, 13 SKZX => 8 MQPH 2 | 10 LSLV => 4 JNJHW 3 | 1 MQGF, 4 ZWXDQ, 1 GNSZ => 9 DGDH 4 | 1 SKZX, 3 DJSP => 1 MCHV 5 | 6 TWSR, 10 ZHDFS, 10 LQZXQ => 9 LXQNX 6 | 1 FRVW, 1 CJTW => 9 BRCB 7 | 20 ZHVNP => 8 XMXL 8 | 7 JQJXP => 1 ZGZDW 9 | 13 KRCM => 6 KXPQ 10 | 4 ZWXDQ, 4 KFKQF, 1 DZDX => 2 MQGF 11 | 8 DZDX, 2 ZKGM => 3 KFKQF 12 | 3 FXFTB => 8 KVDGP 13 | 10 MVGLF, 3 MWFBW, 13 XMXL, 1 CJTW, 2 ZSXJZ, 2 TNCZH, 3 MPFKN, 6 LXQNX => 2 MZMZQ 14 | 5 FRVW => 3 NWBTP 15 | 1 MVGLF, 2 NLXD, 6 KVDGP, 2 MQPH, 4 FXTJ, 10 TKXKF, 2 FRWV => 2 CSNS 16 | 13 TWSR => 9 BNWT 17 | 2 KRCM => 7 LSLV 18 | 1 ZHDFS, 11 NTVZD, 1 JQJXP => 6 ZHVNP 19 | 2 MCHV, 1 JNJHW => 6 NDQNH 20 | 32 SMHJH, 6 KXPQ => 1 CJTW 21 | 15 FXFTB, 1 MVGLF => 9 MPFKN 22 | 119 ORE => 9 KRCM 23 | 3 TNCZH => 9 BFQLT 24 | 5 MPFKN, 7 TKXKF, 6 JQJXP, 2 DZDX, 16 LCQJ, 4 DGDH, 4 ZGZDW => 7 WVXW 25 | 1 ZHDFS, 1 LXQNX => 3 TNCZH 26 | 4 ZMVKM, 1 BRQT => 3 QHSZD 27 | 24 FRVW, 1 KVDGP, 2 ZLNM => 3 FGLNK 28 | 2 KXPQ, 1 LSLV, 22 HNRQ => 5 ZWXDQ 29 | 6 ZWXDQ => 1 FRVW 30 | 1 FXFTB, 2 MWFBW => 6 ZHDFS 31 | 32 FRVW => 5 FRWV 32 | 6 FXFTB, 6 NDQNH, 2 MWFBW => 1 JQJXP 33 | 9 ZMVKM, 6 QHSZD, 5 LSLV => 4 SMHJH 34 | 3 CHKZ => 6 HLJD 35 | 21 BFQLT => 6 FXTJ 36 | 1 SMHJH, 4 FXFTB => 6 CHKZ 37 | 13 FRVW, 13 JQJXP, 1 GNSZ => 8 ZSXJZ 38 | 2 NDQNH => 8 NTVZD 39 | 3 KRCM => 2 ZKGM 40 | 13 ZHDFS, 14 ZWXDQ, 1 CHKZ => 7 LQZXQ 41 | 2 BNWT, 3 CHKZ => 7 ZLNM 42 | 167 ORE => 1 BRQT 43 | 1 LSLV => 3 DZDX 44 | 8 MZMZQ, 7 NWBTP, 3 WVXW, 44 MQPH, 3 DJSP, 1 CSNS, 3 BRCB, 32 LQZXQ => 1 FUEL 45 | 8 ZLNM => 2 NLXD 46 | 30 JQJXP, 9 FGLNK => 7 LCQJ 47 | 1 ZKGM, 19 KXPQ => 8 DJSP 48 | 4 DJSP => 6 FXFTB 49 | 25 NFTPZ => 6 ZMVKM 50 | 14 ZHVNP, 1 MVGLF => 9 TKXKF 51 | 1 BRQT => 2 SKZX 52 | 6 ZKGM => 7 HNRQ 53 | 3 DZDX => 5 TWSR 54 | 1 SMHJH => 7 MVGLF 55 | 3 NDQNH => 1 GNSZ 56 | 153 ORE => 9 NFTPZ 57 | 14 MCHV, 4 JNJHW, 2 DJSP => 4 MWFBW 58 | -------------------------------------------------------------------------------- /2019/input/16.txt: -------------------------------------------------------------------------------- 1 | 59728839950345262750652573835965979939888018102191625099946787791682326347549309844135638586166731548034760365897189592233753445638181247676324660686068855684292956604998590827637221627543512414238407861211421936232231340691500214827820904991045564597324533808990098343557895760522104140762068572528148690396033860391137697751034053950225418906057288850192115676834742394553585487838826710005579833289943702498162546384263561449255093278108677331969126402467573596116021040898708023407842928838817237736084235431065576909382323833184591099600309974914741618495832080930442596854495321267401706790270027803358798899922938307821234896434934824289476011 2 | -------------------------------------------------------------------------------- /2019/input/19.txt: -------------------------------------------------------------------------------- 1 | 109,424,203,1,21101,11,0,0,1106,0,282,21102,1,18,0,1105,1,259,1202,1,1,221,203,1,21101,0,31,0,1105,1,282,21102,1,38,0,1106,0,259,21001,23,0,2,22102,1,1,3,21102,1,1,1,21102,57,1,0,1106,0,303,2101,0,1,222,21002,221,1,3,21001,221,0,2,21101,0,259,1,21101,80,0,0,1105,1,225,21101,158,0,2,21101,0,91,0,1106,0,303,1201,1,0,223,20102,1,222,4,21101,259,0,3,21101,225,0,2,21102,225,1,1,21101,118,0,0,1106,0,225,20102,1,222,3,21101,0,79,2,21102,1,133,0,1106,0,303,21202,1,-1,1,22001,223,1,1,21101,148,0,0,1105,1,259,2102,1,1,223,21001,221,0,4,20102,1,222,3,21101,16,0,2,1001,132,-2,224,1002,224,2,224,1001,224,3,224,1002,132,-1,132,1,224,132,224,21001,224,1,1,21101,0,195,0,106,0,108,20207,1,223,2,20101,0,23,1,21102,-1,1,3,21102,214,1,0,1106,0,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,1201,-4,0,249,21202,-3,1,1,21201,-2,0,2,22101,0,-1,3,21101,250,0,0,1106,0,225,21202,1,1,-4,109,-5,2105,1,0,109,3,22107,0,-2,-1,21202,-1,2,-1,21201,-1,-1,-1,22202,-1,-2,-2,109,-3,2106,0,0,109,3,21207,-2,0,-1,1206,-1,294,104,0,99,21202,-2,1,-2,109,-3,2106,0,0,109,5,22207,-3,-4,-1,1206,-1,346,22201,-4,-3,-4,21202,-3,-1,-1,22201,-4,-1,2,21202,2,-1,-1,22201,-4,-1,1,22101,0,-2,3,21102,343,1,0,1106,0,303,1106,0,415,22207,-2,-3,-1,1206,-1,387,22201,-3,-2,-3,21202,-2,-1,-1,22201,-3,-1,3,21202,3,-1,-1,22201,-3,-1,2,22101,0,-4,1,21101,384,0,0,1105,1,303,1105,1,415,21202,-4,-1,-4,22201,-4,-3,-4,22202,-3,-2,-2,22202,-2,-4,-4,22202,-3,-2,-3,21202,-4,-1,-2,22201,-3,-2,1,21202,1,1,-4,109,-5,2106,0,0 2 | -------------------------------------------------------------------------------- /2019/input/2.txt: -------------------------------------------------------------------------------- 1 | 1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,9,19,1,10,19,23,2,9,23,27,1,6,27,31,2,31,9,35,1,5,35,39,1,10,39,43,1,10,43,47,2,13,47,51,1,10,51,55,2,55,10,59,1,9,59,63,2,6,63,67,1,5,67,71,1,71,5,75,1,5,75,79,2,79,13,83,1,83,5,87,2,6,87,91,1,5,91,95,1,95,9,99,1,99,6,103,1,103,13,107,1,107,5,111,2,111,13,115,1,115,6,119,1,6,119,123,2,123,13,127,1,10,127,131,1,131,2,135,1,135,5,0,99,2,14,0,0 2 | -------------------------------------------------------------------------------- /2019/input/24.txt: -------------------------------------------------------------------------------- 1 | ##### 2 | .#.## 3 | #...# 4 | ..### 5 | #.##. 6 | -------------------------------------------------------------------------------- /2019/input/4.txt: -------------------------------------------------------------------------------- 1 | 123257-647015 2 | -------------------------------------------------------------------------------- /2019/input/7.txt: -------------------------------------------------------------------------------- 1 | 3,8,1001,8,10,8,105,1,0,0,21,42,67,88,101,114,195,276,357,438,99999,3,9,101,3,9,9,1002,9,4,9,1001,9,5,9,102,4,9,9,4,9,99,3,9,1001,9,3,9,1002,9,2,9,101,2,9,9,102,2,9,9,1001,9,5,9,4,9,99,3,9,102,4,9,9,1001,9,3,9,102,4,9,9,101,4,9,9,4,9,99,3,9,101,2,9,9,1002,9,3,9,4,9,99,3,9,101,4,9,9,1002,9,5,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,99 2 | -------------------------------------------------------------------------------- /2020/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2020 2 | 3 | ![map](./img/map.png) 4 | -------------------------------------------------------------------------------- /2020/day/1.py: -------------------------------------------------------------------------------- 1 | with open('../input/1.txt', 'r') as f: 2 | data = [int(line) for line in f] 3 | 4 | for i, x in enumerate(data): 5 | for j, y in enumerate(data[i:], 1): 6 | if x + y == 2020: 7 | part1 = x * y 8 | for k, z in enumerate(data[i+j:]): 9 | if x + y + z == 2020: 10 | part2 = x * y * z 11 | 12 | print(part1) 13 | print(part2) 14 | -------------------------------------------------------------------------------- /2020/day/10.py: -------------------------------------------------------------------------------- 1 | with open('../input/10.txt') as f: 2 | data = sorted(map(int, f)) 3 | 4 | delta = {1: 0, 3: 1} 5 | joltage = 0 6 | for n in data: 7 | delta[n - joltage] += 1 8 | joltage = n 9 | 10 | print(delta[1] * delta[3]) 11 | 12 | stairs = [1] + [0]*data[-1] 13 | for n in data: 14 | stairs[n] = stairs[n-3] + stairs[n-2] + stairs[n-1] 15 | 16 | print(stairs[-1]) 17 | -------------------------------------------------------------------------------- /2020/day/11.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | from copy import deepcopy 3 | 4 | 5 | def isvalid(row, col): 6 | return 0 <= row < ROWS and 0 <= col < COLUMNS 7 | 8 | 9 | def neighbours1(r, c): 10 | return [(r-1, c-1), (r-1, c+1), (r, c-1), (r+1, c), 11 | (r+1, c+1), (r+1, c-1), (r, c+1), (r-1, c)] 12 | 13 | 14 | def neighbours2(row, col): 15 | n = [] 16 | for delta_r, delta_c in neighbours1(0, 0): 17 | for k in count(1): 18 | r = row + k * delta_r 19 | c = col + k * delta_c 20 | if isvalid(r, c): 21 | if data[r][c] != '.': 22 | n.append((r, c)) 23 | break 24 | else: 25 | break 26 | return n 27 | 28 | 29 | with open('../input/11.txt') as f: 30 | start = list(map(list, f.read().splitlines())) 31 | 32 | ROWS, COLUMNS = len(start), len(start[0]) 33 | 34 | for neighbours, adjecent in [(neighbours1, 4), (neighbours2, 5)]: 35 | data = start 36 | for episode in count(): 37 | data_ = deepcopy(data) 38 | for i, row in enumerate(data): 39 | for j, seat in enumerate(row): 40 | if seat == 'L' and all(data[x][y] != '#' 41 | for x, y in neighbours(i, j) 42 | if isvalid(x, y)): 43 | data_[i][j] = '#' 44 | 45 | elif seat == '#' and sum(data[x][y] == '#' 46 | for x, y in neighbours(i, j) 47 | if isvalid(x, y)) >= adjecent: 48 | data_[i][j] = 'L' 49 | 50 | if data == data_: 51 | print(sum(c == '#' for row in data_ for c in row)) 52 | break 53 | 54 | data = data_ 55 | -------------------------------------------------------------------------------- /2020/day/12.py: -------------------------------------------------------------------------------- 1 | with open('../input/12.txt') as f: # file 2 | data = [(cmd, int(''.join(n))) for cmd, *n in f] 3 | 4 | d = 1 5 | xy = 0 6 | for cmd, n in data: 7 | if cmd == 'F': 8 | xy += d*n 9 | elif cmd == 'L': 10 | d *= 1j**(n//90) 11 | elif cmd == 'R': 12 | d /= 1j**(n//90) 13 | elif cmd == 'N': 14 | xy += n*1j 15 | elif cmd == 'S': 16 | xy -= n*1j 17 | elif cmd == 'E': 18 | xy += n 19 | elif cmd == 'W': 20 | xy -= n 21 | 22 | print(int(abs(xy.real) + abs(xy.imag))) 23 | 24 | xy = 0 25 | w = 10 + 1j 26 | for cmd, n in data: 27 | if cmd == 'F': 28 | xy += n*w 29 | elif cmd == 'L': 30 | w *= 1j**(n//90) 31 | elif cmd == 'R': 32 | w /= 1j**(n//90) 33 | elif cmd == 'N': 34 | w += n*1j 35 | elif cmd == 'S': 36 | w -= n*1j 37 | elif cmd == 'E': 38 | w += n 39 | elif cmd == 'W': 40 | w -= n 41 | 42 | print(int(abs(xy.real) + abs(xy.imag))) 43 | -------------------------------------------------------------------------------- /2020/day/13.py: -------------------------------------------------------------------------------- 1 | from math import prod 2 | from sympy.ntheory.modular import crt 3 | 4 | with open('../input/13.txt') as f: 5 | time = int(next(f)) 6 | busses = [(int(bus), -i) 7 | for i, bus in enumerate(next(f).split(',')) if bus != 'x'] 8 | 9 | print(prod(min((-time % bus, bus) for bus, _ in busses))) 10 | print(crt(*zip(*busses))[0]) 11 | -------------------------------------------------------------------------------- /2020/day/14.py: -------------------------------------------------------------------------------- 1 | import re 2 | from itertools import product 3 | from collections import defaultdict 4 | 5 | mem1 = defaultdict(int) 6 | mem2 = defaultdict(int) 7 | with open('../input/14.txt') as f: 8 | for line in f: 9 | if line.startswith('mask'): 10 | mask = list(line[7:].strip()) 11 | else: 12 | address, n = map(int, re.findall(r'\d+', line)) 13 | n_b = list(format(n, 'b').zfill(36)) 14 | address_b = list(format(address, 'b').zfill(36)) 15 | 16 | x = ''.join(n_bit if mask_bit == 'X' else mask_bit 17 | for mask_bit, n_bit in zip(mask, n_b)) 18 | mem1[address] = int(x, base=2) 19 | 20 | for floating in map(iter, product('10', repeat=mask.count('X'))): 21 | x = ''.join(next(floating) if mask_bit == 'X' else 22 | address_bit if mask_bit == '0' else '1' 23 | for mask_bit, address_bit in zip(mask, address_b)) 24 | mem2[int(x, base=2)] = n 25 | 26 | 27 | print(sum(mem1.values())) 28 | print(sum(mem2.values())) 29 | -------------------------------------------------------------------------------- /2020/day/15.py: -------------------------------------------------------------------------------- 1 | with open('../input/15.txt') as f: 2 | data = list(map(int, f.read().split(','))) 3 | 4 | seen = {last: i + 1 for i, last in enumerate(data)} 5 | last = data[-1] 6 | 7 | for turn in range(len(data) + 1, 30000000 + 1): 8 | current = turn - 1 - seen[last] if last in seen else 0 9 | seen[last] = turn - 1 10 | last = current 11 | if turn == 2020: 12 | print(current) 13 | 14 | print(current) 15 | -------------------------------------------------------------------------------- /2020/day/16.py: -------------------------------------------------------------------------------- 1 | from math import prod 2 | 3 | with open('../input/16.txt') as f: 4 | fields, my_ticket, tickets = [chunk.split('\n') 5 | for chunk in f.read().strip().split('\n\n')] 6 | 7 | rules = dict() 8 | for line in fields: 9 | key, ranges = line.split(': ') 10 | rules[key] = [list(map(int, r.split('-'))) for r in ranges.split('or')] 11 | 12 | my_ticket = list(map(int, my_ticket[1].split(','))) 13 | tickets = [list(map(int, line.split(','))) for line in tickets[1:]] 14 | 15 | error = 0 16 | wrong = set() 17 | for i, ticket in enumerate(tickets): 18 | for n in ticket: 19 | if all(lo > n or n > hi for rule in rules for lo, hi in rules[rule]): 20 | error += n 21 | wrong.add(i) 22 | 23 | print(error) 24 | 25 | columns = [set(rules.keys()) for _ in range(len(tickets[0]))] 26 | for i, ticket in enumerate(tickets): 27 | if i not in wrong: 28 | for rule in rules: 29 | for j, n in enumerate(ticket): 30 | if a := all(n < lo or hi < n for lo, hi in rules[rule]): 31 | columns[j] -= {rule} 32 | 33 | change = True 34 | while change: 35 | change = False 36 | for i, column in enumerate(columns): 37 | if len(column) == 1: 38 | for j, column2 in enumerate(columns): 39 | if i != j and column & column2: 40 | columns[j] -= column 41 | change = True 42 | 43 | print(prod(n for c, n in zip(columns, my_ticket) if 'departure' in c.pop())) 44 | -------------------------------------------------------------------------------- /2020/day/17.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | from collections import defaultdict 3 | 4 | 5 | def count_active(active, dimension, cycles=6): 6 | active = set((0,) * (dimension-2) + cube for cube in active) 7 | for _ in range(cycles): 8 | new_active = set() 9 | neighbours = defaultdict(int) 10 | for cube in active: 11 | for offset in product((-1, 0, 1), repeat=dimension): 12 | if offset != (0,) * dimension: 13 | neighbour = tuple(x + dx for x, dx in zip(cube, offset)) 14 | neighbours[neighbour] += 1 15 | 16 | for cube, n in neighbours.items(): 17 | if cube in active and n in [2, 3]: 18 | new_active.add(cube) 19 | 20 | elif cube not in active and n == 3: 21 | new_active.add(cube) 22 | 23 | active = new_active 24 | return len(active) 25 | 26 | 27 | with open('../input/17.txt') as f: 28 | active = set((r, c) for r, line in enumerate(f.read().splitlines()) 29 | for c, n in enumerate(line) if n == '#') 30 | 31 | print(count_active(active, 3)) 32 | print(count_active(active, 4)) 33 | -------------------------------------------------------------------------------- /2020/day/18.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | class Int(int): 5 | def __mul__(self, o): 6 | return Int(int(o) + self) 7 | 8 | def __add__(self, o): 9 | return Int(int(o) + self) 10 | 11 | def __sub__(self, o): 12 | return Int(int(o) * self) 13 | 14 | 15 | s1 = s2 = 0 16 | with open('../input/18.txt') as f: 17 | for line in f.read().splitlines(): 18 | line = line.replace('*', '-') 19 | s1 += eval(re.sub(r'(\d+)', r'Int(\1)', line)) 20 | s2 += eval(re.sub(r'(\d+)', r'Int(\1)', line.replace('+', '*'))) 21 | 22 | print(s1) 23 | print(s2) 24 | -------------------------------------------------------------------------------- /2020/day/19.py: -------------------------------------------------------------------------------- 1 | from lark import Lark, LarkError 2 | from contextlib import suppress 3 | 4 | 5 | def solve(rules, messages): 6 | rules = rules.translate(str.maketrans('0123456789', 'abcdefghij')) 7 | parser = Lark(rules, start='a') 8 | match = 0 9 | for line in messages.splitlines(): 10 | with suppress(LarkError): 11 | parser.parse(line) 12 | match += 1 13 | return match 14 | 15 | 16 | with open('../input/19.txt') as f: 17 | rules, messages = f.read().split('\n\n') 18 | 19 | print(solve(rules, messages)) 20 | rules = rules.replace('8: 42', '8: 42 | 42 8') 21 | rules = rules.replace('11: 42 31', '11: 42 31 | 42 11 31') 22 | print(solve(rules, messages)) 23 | -------------------------------------------------------------------------------- /2020/day/2.py: -------------------------------------------------------------------------------- 1 | s1 = s2 = 0 2 | with open('../input/2.txt') as f: 3 | for line in f: 4 | numbers, char, password = line.split() 5 | lo, hi = map(int, numbers.split('-')) 6 | char = char[0] 7 | if lo <= password.count(char) <= hi: 8 | s1 += 1 9 | 10 | if (password[lo-1] == char) ^ (password[hi-1] == char): 11 | s2 += 1 12 | 13 | print(s1) 14 | print(s2) 15 | -------------------------------------------------------------------------------- /2020/day/21.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | data = [] 4 | with open('../input/21.txt') as f: 5 | for line in f: 6 | i, a = line.split('(') 7 | data.append((i.split(), a[9:-2].split(', '))) 8 | 9 | food = defaultdict(set) 10 | for ingridients, allergens in data: 11 | for ingridient in ingridients: 12 | for allergen in allergens: 13 | food[allergen].add(ingridient) 14 | 15 | for ingridients, allergens in data: 16 | for allergen in allergens: 17 | for ingridient in set(food[allergen]): 18 | if ingridient not in ingridients: 19 | food[allergen].remove(ingridient) 20 | 21 | visit = {allergen for allergen in food if len(food[allergen]) == 1} 22 | seen = set(visit) 23 | while visit: 24 | allergen = visit.pop() 25 | ingridient = next(iter(food[allergen])) 26 | for a, i in food.items(): 27 | if len(i) > 1: 28 | if ingridient in i: 29 | food[a].remove(ingridient) 30 | if len(food[a]) == 1: 31 | visit.add(a) 32 | 33 | toxic = set.union(*food.values()) 34 | d = dict((v.pop(), k) for k, v in food.items()) 35 | 36 | print(sum(ingridient not in toxic 37 | for ingridients, a in data 38 | for ingridient in ingridients)) 39 | print(','.join(sorted(d.keys(), key=lambda k: d[k]))) 40 | -------------------------------------------------------------------------------- /2020/day/22.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | 4 | def game(p1, p2, recurse=True): 5 | seen = set() 6 | while p1 and p2: 7 | t = (tuple(p1), tuple(p2)) 8 | if t in seen: 9 | return p1, True 10 | 11 | seen.add(t) 12 | c1 = p1.popleft() 13 | c2 = p2.popleft() 14 | if recurse and c1 <= len(p1) and c2 <= len(p2): 15 | if game(deque(e for i, e in enumerate(p1) if i < c1), 16 | deque(e for i, e in enumerate(p2) if i < c2))[1]: 17 | p1.extend([c1, c2]) 18 | else: 19 | p2.extend([c2, c1]) 20 | 21 | elif c1 > c2: 22 | p1.extend([c1, c2]) 23 | else: 24 | p2.extend([c2, c1]) 25 | 26 | return (p1, True) if p1 else (p2, False) 27 | 28 | 29 | with open('../input/22.txt') as f: 30 | p1, p2 = f.read().split('\n\n') 31 | p1 = deque(map(int, p1.splitlines()[1:])) 32 | p2 = deque(map(int, p2.splitlines()[1:])) 33 | 34 | 35 | winner = game(deque(p1), deque(p2), recurse=False)[0] 36 | print(sum(i*j for i, j in enumerate(reversed(winner), 1))) 37 | winner = game(p1, p2)[0] 38 | print(sum(i*j for i, j in enumerate(reversed(winner), 1))) 39 | -------------------------------------------------------------------------------- /2020/day/23.py: -------------------------------------------------------------------------------- 1 | def emulate(d, label, iterations): 2 | for _ in range(iterations): 3 | left = d[label] 4 | middle = d[left] 5 | right = d[middle] 6 | dest = (label - 2) % size + 1 7 | while dest in (left, middle, right): 8 | dest = (dest - 2) % size + 1 9 | 10 | d[label], d[dest], d[right] = d[right], left, d[dest] 11 | label = d[label] 12 | return d 13 | 14 | 15 | with open('../input/23.txt') as f: 16 | data = list(map(int, f.read().strip())) 17 | 18 | size = len(data) 19 | d = [1]*(size + 1) 20 | for i, e in enumerate(data): 21 | d[e] = data[(i+2) % size - 1] 22 | 23 | d1 = emulate(d[:], data[0], 100) 24 | 25 | in_order = [d1[1]] 26 | for _ in range(size - 2): 27 | in_order.append(d1[in_order[-1]]) 28 | 29 | print(''.join(map(str, in_order))) 30 | 31 | d[data[-1]] = size + 1 32 | size, iterations = 10**6, 10**7 33 | d = d + list(range(len(d) + 1, size + 1)) + [data[0]] 34 | d = emulate(d, data[0], iterations) 35 | print(d[1] * d[d[1]]) 36 | -------------------------------------------------------------------------------- /2020/day/24.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | import re 3 | 4 | d = { 5 | 'e': 1, 6 | 'se': 0.5+1j, 7 | 'ne': 0.5-1j, 8 | 'w': -1, 9 | 'sw': -0.5+1j, 10 | 'nw': -0.5-1j, 11 | } 12 | 13 | grid = defaultdict(bool) 14 | with open('../input/24.txt') as f: 15 | for line in f: 16 | grid[sum(d[cmd] for cmd in re.findall('e|se|ne|w|sw|nw', line))] ^= 1 17 | 18 | print(sum(grid.values())) 19 | 20 | for i in range(100): 21 | for tile in grid.keys(): 22 | for n in d.values(): 23 | grid[tile+n] 24 | 25 | grid_ = grid.copy() 26 | for tile in grid_.keys(): 27 | bt = sum(grid[tile+n] for n in d.values()) 28 | if grid[tile] and (bt == 0 or bt > 2): 29 | grid_[tile] ^= 1 30 | elif not grid[tile] and bt == 2: 31 | grid_[tile] ^= 1 32 | grid = grid_ 33 | 34 | print(sum(grid.values())) 35 | -------------------------------------------------------------------------------- /2020/day/25.py: -------------------------------------------------------------------------------- 1 | with open('../input/25.txt') as f: 2 | me, door = keys = set(map(int, f)) 3 | 4 | mod = 20201227 5 | loop_size = 1 6 | subject = 7 7 | for loop_size in range(10**10): 8 | if (public := pow(subject, loop_size, mod)) in keys: 9 | print(pow(me if public == door else door, loop_size, mod)) 10 | break 11 | -------------------------------------------------------------------------------- /2020/day/3.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | 3 | with open('../input/3.txt') as f: 4 | data = [line.strip() for line in f] 5 | 6 | product = 1 7 | for x, y in [(1, 1), (5, 1), (7, 1), (1, 2), (3, 1)]: 8 | trees = 0 9 | for row, col in zip(range(0, len(data), y), count(0, x)): 10 | if data[row][col % len(data[0])] == '#': 11 | trees += 1 12 | 13 | product *= trees 14 | 15 | print(trees) 16 | print(product) 17 | -------------------------------------------------------------------------------- /2020/day/4.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open('../input/4.txt') as f: 4 | passports = [p.replace('\n', ' ') for p in f.read().strip().split('\n\n')] 5 | 6 | keys = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'] 7 | valid1 = valid2 = 0 8 | for passport in passports: 9 | d = dict(field.split(':') for field in passport.split()) 10 | if all(key in d for key in keys): 11 | valid1 += 1 12 | if 1920 <= int(d['byr']) <= 2002\ 13 | and 2010 <= int(d['iyr']) <= 2020\ 14 | and 2020 <= int(d['eyr']) <= 2030\ 15 | and re.match(r'\d+..', d['hgt'])\ 16 | and (d['hgt'].endswith('cm') and 150 <= int(d['hgt'][:-2]) <= 193 or d['hgt'].endswith('in') and 59 <= int(d['hgt'][:-2]) <= 76)\ 17 | and re.match(r'^#[\da-f]{6}$', d['hcl'])\ 18 | and d['ecl'] in ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth']\ 19 | and re.match(r'^\d{9}$', d['pid']): 20 | valid2 += 1 21 | 22 | print(valid1) 23 | print(valid2) 24 | -------------------------------------------------------------------------------- /2020/day/5.py: -------------------------------------------------------------------------------- 1 | with open('../input/5.txt') as f: 2 | ids = list(sorted(int(''.join('01'[c in 'BR'] for c in line), base=2) 3 | for line in f.read().splitlines())) 4 | 5 | print(ids[-1]) 6 | print(next(e+1 for i, e in enumerate(ids) if e+1 != ids[i+1])) 7 | -------------------------------------------------------------------------------- /2020/day/6.py: -------------------------------------------------------------------------------- 1 | with open('../input/6.txt') as f: 2 | data = f.read().strip().split('\n\n') 3 | 4 | print(sum(len(set.union(*map(set, x.split('\n')))) for x in data)) 5 | print(sum(len(set.intersection(*map(set, x.split('\n')))) for x in data)) 6 | -------------------------------------------------------------------------------- /2020/day/7.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def contains(trait): 5 | traits = [t for t in data if trait in data[t]] 6 | return [trait, *[t for tr in traits for t in contains(tr)]] 7 | 8 | 9 | def number(trait): 10 | return sum(data[trait][t] * (1 + number(t)) for t in data[trait]) 11 | 12 | 13 | data = {} 14 | with open('../input/7.txt') as f: 15 | for line in f: 16 | trait = re.match(r'(\w+ \w+)', line)[0] 17 | inside = {t: int(n) for n, t in re.findall(r'(\d+) (\w+ \w+)', line)} 18 | data[trait] = inside 19 | 20 | print(len(set(contains('shiny gold'))) - 1) 21 | print(number('shiny gold')) 22 | -------------------------------------------------------------------------------- /2020/day/8.py: -------------------------------------------------------------------------------- 1 | def program(data): 2 | seen = set() 3 | acc = pc = 0 4 | while 0 <= pc < len(data) and pc not in seen: 5 | i, n = data[pc].split() 6 | seen.add(pc) 7 | if i == 'a': 8 | acc += int(n) 9 | elif i == 'j': 10 | pc += int(n) 11 | continue 12 | pc += 1 13 | 14 | return pc, acc 15 | 16 | 17 | with open('../input/8.txt') as f: 18 | data = [line[0] + line[3:] for line in f] 19 | 20 | print(program(data)[1]) 21 | for j in range(len(data)): 22 | if 'a' not in data[j]: 23 | data[j] = data[j].translate(str.maketrans('nj', 'jn')) 24 | pc, acc = program(data) 25 | data[j] = data[j].translate(str.maketrans('nj', 'jn')) 26 | if pc == len(data): 27 | print(acc) 28 | break 29 | -------------------------------------------------------------------------------- /2020/day/9.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | with open('../input/9.txt') as f: 4 | data = list(map(int, f)) 5 | 6 | preamble = deque(data[:25]) 7 | for target in data[25:]: 8 | if all(target - i not in preamble for i in preamble): 9 | print(target) 10 | break 11 | 12 | preamble.popleft() 13 | preamble.append(target) 14 | 15 | running_sum = 0 16 | contiguous_set = deque() 17 | for n in data: 18 | running_sum += n 19 | contiguous_set.append(n) 20 | while running_sum > target: 21 | running_sum -= contiguous_set.popleft() 22 | 23 | if running_sum == target and len(contiguous_set) > 1: 24 | print(min(contiguous_set) + max(contiguous_set)) 25 | break 26 | -------------------------------------------------------------------------------- /2020/img/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2020/img/map.png -------------------------------------------------------------------------------- /2020/input/10.txt: -------------------------------------------------------------------------------- 1 | 59 2 | 134 3 | 159 4 | 125 5 | 95 6 | 92 7 | 169 8 | 43 9 | 154 10 | 46 11 | 110 12 | 79 13 | 117 14 | 151 15 | 141 16 | 56 17 | 87 18 | 10 19 | 65 20 | 170 21 | 89 22 | 32 23 | 40 24 | 118 25 | 36 26 | 94 27 | 124 28 | 173 29 | 164 30 | 166 31 | 113 32 | 67 33 | 76 34 | 102 35 | 107 36 | 52 37 | 144 38 | 119 39 | 2 40 | 72 41 | 86 42 | 73 43 | 66 44 | 13 45 | 15 46 | 38 47 | 47 48 | 109 49 | 103 50 | 128 51 | 165 52 | 148 53 | 116 54 | 146 55 | 18 56 | 135 57 | 68 58 | 83 59 | 133 60 | 171 61 | 145 62 | 48 63 | 31 64 | 106 65 | 161 66 | 6 67 | 21 68 | 22 69 | 77 70 | 172 71 | 28 72 | 78 73 | 96 74 | 55 75 | 132 76 | 39 77 | 100 78 | 108 79 | 33 80 | 23 81 | 54 82 | 157 83 | 80 84 | 153 85 | 9 86 | 62 87 | 26 88 | 147 89 | 1 90 | 27 91 | 131 92 | 88 93 | 138 94 | 93 95 | 14 96 | 123 97 | 122 98 | 158 99 | 152 100 | 71 101 | 49 102 | 101 103 | 37 104 | 99 105 | 160 106 | 53 107 | 3 108 | -------------------------------------------------------------------------------- /2020/input/13.txt: -------------------------------------------------------------------------------- 1 | 1001612 2 | 19,x,x,x,x,x,x,x,x,41,x,x,x,37,x,x,x,x,x,821,x,x,x,x,x,x,x,x,x,x,x,x,13,x,x,x,17,x,x,x,x,x,x,x,x,x,x,x,29,x,463,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,23 3 | -------------------------------------------------------------------------------- /2020/input/15.txt: -------------------------------------------------------------------------------- 1 | 20,0,1,11,6,3 2 | -------------------------------------------------------------------------------- /2020/input/17.txt: -------------------------------------------------------------------------------- 1 | .#.####. 2 | .#...##. 3 | ..###.## 4 | #..#.#.# 5 | #..#.... 6 | #.####.. 7 | ##.##..# 8 | #.#.#..# 9 | -------------------------------------------------------------------------------- /2020/input/22.txt: -------------------------------------------------------------------------------- 1 | Player 1: 2 | 24 3 | 22 4 | 26 5 | 6 6 | 14 7 | 19 8 | 27 9 | 17 10 | 39 11 | 34 12 | 40 13 | 41 14 | 23 15 | 30 16 | 36 17 | 11 18 | 28 19 | 3 20 | 10 21 | 21 22 | 9 23 | 50 24 | 32 25 | 25 26 | 8 27 | 28 | Player 2: 29 | 48 30 | 49 31 | 47 32 | 15 33 | 42 34 | 44 35 | 5 36 | 4 37 | 13 38 | 7 39 | 20 40 | 43 41 | 12 42 | 37 43 | 29 44 | 18 45 | 45 46 | 16 47 | 1 48 | 46 49 | 38 50 | 35 51 | 2 52 | 33 53 | 31 54 | -------------------------------------------------------------------------------- /2020/input/23.txt: -------------------------------------------------------------------------------- 1 | 193467258 2 | -------------------------------------------------------------------------------- /2020/input/25.txt: -------------------------------------------------------------------------------- 1 | 18499292 2 | 8790390 3 | -------------------------------------------------------------------------------- /2021/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2021 2 | 3 | ![depths](./img/depths.png) 4 | -------------------------------------------------------------------------------- /2021/day/1.py: -------------------------------------------------------------------------------- 1 | with open("../input/1.txt") as f: 2 | depths = list(map(int, f.readlines())) 3 | 4 | print(sum(depths[i - 1] < depths[i] for i in range(1, len(depths)))) 5 | print(sum(current > last for last, current in zip(depths, depths[3:]))) 6 | -------------------------------------------------------------------------------- /2021/day/10.py: -------------------------------------------------------------------------------- 1 | with open("../input/10.txt") as f: 2 | data = f.readlines() 3 | 4 | matching_parenthesis = {"(": ")", "[": "]", "{": "}", "<": ">"} 5 | corrupted_score = {")": 3, "]": 57, "}": 1197, ">": 25137} 6 | incomplete_score = {")": 1, "]": 2, "}": 3, ">": 4} 7 | 8 | part_1 = 0 9 | part_2 = [] 10 | for line in data: 11 | stack = [] 12 | for c in line.strip(): 13 | if c in ")]}>": 14 | if stack.pop() != c: 15 | part_1 += corrupted_score[c] 16 | break 17 | else: 18 | stack.append(matching_parenthesis[c]) 19 | else: 20 | score = 0 21 | for c in reversed(stack): 22 | score = score * 5 + incomplete_score[c] 23 | 24 | part_2.append(score) 25 | 26 | print(part_1) 27 | print(sorted(part_2)[len(part_2) // 2]) 28 | -------------------------------------------------------------------------------- /2021/day/11.py: -------------------------------------------------------------------------------- 1 | data = {} 2 | with open("../input/11.txt") as f: 3 | for y, row in enumerate(f.readlines()): 4 | for x, n in enumerate(row.strip()): 5 | data[(x, y)] = int(n) 6 | 7 | border = ((1, -1), (1, 0), (1, 1), (0, -1), (0, 1), (-1, -1), (-1, 0), (-1, 1)) 8 | step = 0 9 | total_flashes = 0 10 | while True: 11 | step += 1 12 | for key in data: 13 | data[key] += 1 14 | 15 | stack = [key for key in data if data[key] == 10] 16 | while stack: 17 | x, y = stack.pop() 18 | for dx, dy in border: 19 | x_ = x + dx 20 | y_ = y + dy 21 | if (x_, y_) in data and data[x_, y_] < 10: 22 | data[x_, y_] += 1 23 | if data[x_, y_] == 10: 24 | stack.append((x_, y_)) 25 | 26 | flashes = 0 27 | for key in data: 28 | if data[key] == 10: 29 | data[key] = 0 30 | flashes += 1 31 | 32 | total_flashes += flashes 33 | if step == 100: 34 | print(total_flashes) 35 | 36 | if flashes == 100: 37 | print(step) 38 | break 39 | -------------------------------------------------------------------------------- /2021/day/12.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | def dfs(start, seen, part_2=False): 5 | if start == "end": 6 | return 1 7 | 8 | s = 0 9 | for end in d[start]: 10 | if end not in seen: 11 | tmp = {end} if end.islower() else set() 12 | s += dfs(end, seen | tmp, part_2) 13 | elif part_2 and end != "start": 14 | s += dfs(end, seen, False) 15 | 16 | return s 17 | 18 | 19 | with open("../input/12.txt") as f: 20 | data = f.readlines() 21 | 22 | d = defaultdict(set) 23 | for line in data: 24 | start, end = line.strip().split("-") 25 | d[start].add(end) 26 | d[end].add(start) 27 | 28 | print(dfs("start", {"start"})) 29 | print(dfs("start", {"start"}, True)) 30 | -------------------------------------------------------------------------------- /2021/day/13.py: -------------------------------------------------------------------------------- 1 | with open("../input/13.txt") as f: 2 | points, folds = f.read().strip().split("\n\n") 3 | 4 | points = {tuple(map(int, line.split(","))) for line in points.split("\n")} 5 | for i, line in enumerate(folds.split("\n")): 6 | coordinate, n = line.split()[-1].split("=") 7 | n = int(n) 8 | for x, y in list(points): 9 | points.remove((x, y)) 10 | if coordinate == "x" and x > n: 11 | x = 2 * n - x 12 | 13 | if coordinate == "y" and y > n: 14 | y = 2 * n - y 15 | 16 | points.add((x, y)) 17 | 18 | if i == 0: 19 | print(len(points)) 20 | 21 | X, Y = zip(*points) 22 | for y in range(max(Y) + 1): 23 | for x in range(max(X) + 1): 24 | print(" #"[(x, y) in points], end="") 25 | 26 | print() 27 | -------------------------------------------------------------------------------- /2021/day/14.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | with open("../input/14.txt") as f: 4 | molecule, lines = data = f.read().strip().split("\n\n") 5 | 6 | d = dict(line.split(" -> ") for line in lines.split("\n")) 7 | 8 | counter = Counter([molecule[i:i+2] for i in range(len(molecule) - 1)]) 9 | for step in range(1, 41): 10 | new_counter = Counter() 11 | for pair in counter: 12 | left, right = pair 13 | mid = d[pair] 14 | new_counter[left + mid] += counter[pair] 15 | new_counter[mid + right] += counter[pair] 16 | 17 | counter = new_counter 18 | if step in [10, 40]: 19 | char_counter = Counter() 20 | for pair in counter: 21 | left, right = pair 22 | char_counter[left] += counter[pair] 23 | char_counter[molecule[-1]] += 1 24 | 25 | print(max(char_counter.values()) - min(char_counter.values())) 26 | -------------------------------------------------------------------------------- /2021/day/15.py: -------------------------------------------------------------------------------- 1 | from heapq import heappop, heappush 2 | 3 | with open("../input/15.txt") as f: 4 | data = [list(map(int, line)) for line in f.read().strip().split("\n")] 5 | 6 | 7 | def shortest_distance(t): 8 | heap = [(0, 0, 0)] 9 | seen = {(0, 0)} 10 | while heap: 11 | distance, x, y = heappop(heap) 12 | if x == t * len(data) - 1 and y == t * len(data[0]) - 1: 13 | return distance 14 | 15 | for dx, dy in ((0, 1), (0, -1), (1, 0), (-1, 0)): 16 | x_, y_ = x + dx, y + dy 17 | if x_ < 0 or y_ < 0 or x_ >= t * len(data) or y_ >= t * len(data): 18 | continue 19 | 20 | a, am = divmod(x_, len(data)) 21 | b, bm = divmod(y_, len(data[0])) 22 | n = ((data[am][bm] + a + b) - 1) % 9 + 1 23 | 24 | if (x_, y_) not in seen: 25 | seen.add((x_, y_)) 26 | heappush(heap, (distance + n, x_, y_)) 27 | 28 | 29 | print(shortest_distance(1)) 30 | print(shortest_distance(5)) 31 | -------------------------------------------------------------------------------- /2021/day/17.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open("../input/17.txt") as f: 4 | xmin, xmax, ymin, ymax = map(int, re.findall(r"[-\d]+", f.read())) 5 | 6 | print(abs(ymin) * abs(ymin + 1) // 2) 7 | 8 | velocities = 0 9 | for dx_init in range(min(0, xmin - 1), max(0, xmax + 1)): 10 | for dy_init in range(ymin, abs(ymin)): 11 | solved = False 12 | dx = dx_init 13 | dy = dy_init 14 | x = 0 15 | y = 0 16 | while y > ymin: 17 | x += dx 18 | y += dy 19 | if dx < 0: 20 | dx += 1 21 | if dx > 0: 22 | dx -= 1 23 | dy -= 1 24 | if xmin <= x <= xmax and ymin <= y <= ymax: 25 | velocities += 1 26 | break 27 | 28 | print(velocities) 29 | -------------------------------------------------------------------------------- /2021/day/2.py: -------------------------------------------------------------------------------- 1 | forward = 0 2 | depth_1 = 0 3 | depth_2 = 0 4 | aim = 0 5 | 6 | with open("../input/2.txt") as f: 7 | for line in f: 8 | direction, n = line.split() 9 | n = int(n) 10 | if direction == "forward": 11 | forward += n 12 | depth_2 += aim * n 13 | elif direction == "up": 14 | depth_1 -= n 15 | aim -= n 16 | elif direction == "down": 17 | aim += n 18 | depth_1 += n 19 | 20 | print(forward * depth_1) 21 | print(forward * depth_2) 22 | -------------------------------------------------------------------------------- /2021/day/20.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | 3 | 4 | with open("../input/20.txt") as f: 5 | tape, image = f.read()[:-1].split("\n\n") 6 | 7 | lights = set() 8 | for y, row in enumerate(image.split("\n")): 9 | for x, pixel in enumerate(row): 10 | if pixel == "#": 11 | lights.add((x, y)) 12 | 13 | for step in count(1): 14 | lights_ = set() 15 | minx = min(x for x, y in lights) 16 | maxx = max(x for x, y in lights) 17 | miny = min(y for x, y in lights) 18 | maxy = max(y for x, y in lights) 19 | for y in range(miny - 2, maxy + 2): 20 | for x in range(minx - 2, maxx + 2): 21 | binary = 0 22 | for b in range(3): 23 | for a in range(3): 24 | if (x + a, y + b) in lights: 25 | binary += pow(2, (2 - b) * 3 + (2 - a)) 26 | elif tape[0] == "#" and step % 2 == 0: 27 | if (x + a) < minx or (x + a) > maxx: 28 | binary += pow(2, (2 - b) * 3 + (2 - a)) 29 | elif (y + b) < miny or (y + b) > maxy: 30 | binary += pow(2, (2 - b) * 3 + (2 - a)) 31 | 32 | if tape[binary] == "#": 33 | lights_.add((x + 1, y + 1)) 34 | 35 | lights = lights_ 36 | if step == 2: 37 | print(len(lights)) 38 | 39 | if step == 50: 40 | print(len(lights)) 41 | break 42 | -------------------------------------------------------------------------------- /2021/day/21.py: -------------------------------------------------------------------------------- 1 | from itertools import cycle 2 | from functools import cache 3 | 4 | with open("../input/21.txt") as f: 5 | player_1, player_2 = [int(line[-3:]) for line in f.readlines()] 6 | 7 | 8 | def part_1(player_1, player_2, score_1=0, score_2=0, throws=0): 9 | if score_2 >= 1000: 10 | return score_1 * throws 11 | 12 | player_1 += sum(next(deterministic_die) for _ in range(3)) 13 | player_1 = (player_1 - 1) % 10 + 1 14 | score_1 += player_1 15 | return part_1(player_2, player_1, score_2, score_1, throws + 3) 16 | 17 | 18 | @cache 19 | def part_2(player_1, player_2, score_1, score_2): 20 | if score_2 >= 21: 21 | return (0, 1) 22 | 23 | wins = [0, 0] 24 | for die, throws in zip(range(3, 10), (1, 3, 6, 7, 6, 3, 1)): 25 | new_player_1 = (player_1 + die) % 10 26 | new_score_1 = score_1 + new_player_1 + 1 27 | win_2, win_1 = part_2(player_2, new_player_1, score_2, new_score_1) 28 | wins[0] += win_1 * throws 29 | wins[1] += win_2 * throws 30 | 31 | return wins 32 | 33 | 34 | deterministic_die = cycle(range(1, 101)) 35 | print(part_1(player_1, player_2)) 36 | print(max(part_2(player_1 - 1, player_2 - 1, 0, 0))) 37 | -------------------------------------------------------------------------------- /2021/day/22.py: -------------------------------------------------------------------------------- 1 | import re 2 | from itertools import chain 3 | from bisect import bisect 4 | 5 | with open("../input/22.txt") as f: 6 | data = f.read()[:-1].split("\n") 7 | 8 | cuboids = [] 9 | for line in data: 10 | on, other = line.split() 11 | xmin, xmax, ymin, ymax, zmin, zmax = map(int, re.findall(r"-?\d+", other)) 12 | cuboids.append((on, xmin, xmax + 1, ymin, ymax + 1, zmin, zmax + 1)) 13 | 14 | _, xmins, xmaxs, ymins, ymaxs, zmins, zmaxs = zip(*cuboids) 15 | X = sorted(set(chain(xmins, xmaxs))) 16 | Y = sorted(set(chain(ymins, ymaxs))) 17 | Z = sorted(set(chain(zmins, zmaxs))) 18 | 19 | XA = X[:] 20 | YA = Y[:] 21 | ZA = Z[:] 22 | for i in range(len(X) - 1, 0, -1): 23 | X[i] -= X[i - 1] 24 | for i in range(len(Y) - 1, 0, -1): 25 | Y[i] -= Y[i - 1] 26 | for i in range(len(Z) - 1, 0, -1): 27 | Z[i] -= Z[i - 1] 28 | 29 | small_space = set() 30 | space = set() 31 | for on, xmin, xmax, ymin, ymax, zmin, zmax in cuboids: 32 | for x in range(bisect(XA, xmin) , bisect(XA, xmax)): 33 | for y in range(bisect(YA, ymin) , bisect(YA, ymax)): 34 | for z in range(bisect(ZA, zmin),bisect(ZA, zmax)): 35 | if on == "on": 36 | space.add((x, y, z)) 37 | else: 38 | space.discard((x, y, z)) 39 | 40 | if ( 41 | xmin >= -50 42 | and xmax <= 50 43 | and ymin >= -50 44 | and ymax <= 50 45 | and zmin >= -50 46 | and zmax <= 50 47 | ): 48 | for x in range(xmin, xmax): 49 | for y in range(ymin, ymax): 50 | for z in range(zmin, zmax): 51 | if on == "on": 52 | small_space.add((x, y, z)) 53 | else: 54 | small_space.discard((x, y, z)) 55 | 56 | print(len(small_space)) 57 | print(sum(X[x] * Y[y] * Z[z] for x, y, z in space)) 58 | -------------------------------------------------------------------------------- /2021/day/24.py: -------------------------------------------------------------------------------- 1 | with open("../input/24.txt") as f: 2 | data = f.read().split("inp w\n")[1:] 3 | 4 | z = [] # number in base 26 5 | max_monad = [0] * 14 6 | min_monad = [0] * 14 7 | for i, chunk in enumerate(data): 8 | lines = chunk.split("\n") 9 | pop = int(lines[3][-2:]) == 26 # if digit should be popped from z 10 | x_add = int(lines[4].split()[-1]) 11 | y_add = int(lines[14].split()[-1]) 12 | 13 | if not pop: # push digit to z 14 | z.append((i, y_add)) 15 | else: # apply restriction: last_z_digit == current_z_digit + difference 16 | j, y_add = z.pop() 17 | difference = x_add + y_add 18 | if difference < 0: 19 | max_monad[i] = 9 + difference 20 | max_monad[j] = 9 21 | min_monad[i] = 1 22 | min_monad[j] = 1 - difference 23 | elif difference > 0: 24 | max_monad[i] = 9 25 | max_monad[j] = 9 - difference 26 | min_monad[i] = 1 + difference 27 | min_monad[j] = 1 28 | else: 29 | max_monad[i] = max_monad[j] = 9 30 | min_monad[i] = min_monad[j] = 1 31 | 32 | print("".join(map(str, max_monad))) 33 | print("".join(map(str, min_monad))) 34 | -------------------------------------------------------------------------------- /2021/day/25.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | 3 | 4 | def move(grid, char, func, moved): 5 | moved_grid = grid.copy() 6 | for x, y in grid: 7 | x_, y_ = func(x, y) 8 | if grid[x, y] == char and grid[x_, y_] == ".": 9 | moved_grid[x, y] = "." 10 | moved_grid[x_, y_] = char 11 | moved = True 12 | 13 | return moved_grid, moved 14 | 15 | 16 | with open("../input/25.txt") as f: 17 | data = f.read().strip().split("\n") 18 | 19 | grid = {(x, y): c for y, line in enumerate(data) for x, c in enumerate(line)} 20 | X = max(x for x, _ in grid) + 1 21 | Y = max(y for _, y in grid) + 1 22 | for step in count(1): 23 | grid, moved = move(grid, ">", lambda x, y: ((x + 1) % X, y), False) 24 | grid, moved = move(grid, "v", lambda x, y: (x, (y + 1) % Y), moved) 25 | if not moved: 26 | print(step) 27 | break 28 | -------------------------------------------------------------------------------- /2021/day/3.py: -------------------------------------------------------------------------------- 1 | with open("../input/3.txt") as f: 2 | data = [list(line.strip()) for line in f] 3 | 4 | epsilon = "" 5 | gamma = "" 6 | for bits in zip(*data): 7 | zeros = bits.count("0") 8 | ones = len(data) - zeros 9 | epsilon += "01"[ones > zeros] 10 | gamma += "10"[ones > zeros] 11 | 12 | print(int(epsilon, 2) * int(gamma, 2)) 13 | 14 | 15 | def part_2(codes, common): 16 | for i in range(len(data[0])): 17 | zeros = sum(code[i] == "0" for code in codes) 18 | ones = len(codes) - zeros 19 | common_bit = "01"[(ones >= zeros) ^ common] 20 | codes = [code for code in codes if code[i] == common_bit] 21 | if len(codes) == 1: 22 | return int("".join(codes[0]), 2) 23 | 24 | 25 | print(part_2(data[:], True) * part_2(data[:], False)) 26 | -------------------------------------------------------------------------------- /2021/day/4.py: -------------------------------------------------------------------------------- 1 | with open("../input/4.txt") as f: 2 | numbers = [int(n) for n in f.readline().split(",")] 3 | f.readline() # discard the first empty line 4 | boards = [] 5 | board = [] 6 | for line in f: 7 | if line.strip(): 8 | board.append([[int(n), False] for n in line.split()]) 9 | else: 10 | boards.append(board) 11 | board = [] 12 | 13 | part_1 = None 14 | part_2 = None 15 | seen_boards = set() 16 | for number in numbers: 17 | for board_index, board in enumerate(boards): 18 | if board_index in seen_boards: 19 | continue 20 | 21 | for i, j in ((i, j) for i in range(5) for j in range(5)): 22 | if board[i][j][0] == number: 23 | board[i][j][1] = True 24 | break 25 | else: 26 | continue 27 | 28 | row = all(board[x][j][1] for x in range(5)) 29 | col = all(board[i][y][1] for y in range(5)) 30 | if row or col: 31 | sum_ = sum(x for row in board for x, seen in row if not seen) 32 | 33 | if part_1 is None: 34 | part_1 = sum_ * number 35 | 36 | part_2 = sum_ * number 37 | seen_boards.add(board_index) 38 | 39 | print(part_1) 40 | print(part_2) 41 | -------------------------------------------------------------------------------- /2021/day/5.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | with open("../input/5.txt") as f: 4 | data = f.readlines() 5 | 6 | d = defaultdict(int) 7 | d2 = defaultdict(int) 8 | for line in data: 9 | a, b = line.split('->') 10 | x1, y1 = map(int, a.split(',')) 11 | x2, y2 = map(int, b.split(',')) 12 | if x1 == x2: 13 | for i in range(min(y1, y2), max(y1, y2) + 1): 14 | d[x1, i] += 1 15 | d2[x1, i] += 1 16 | elif y1 == y2: 17 | for i in range(min(x1, x2), max(x1, x2) + 1): 18 | d[i, y1] += 1 19 | d2[i, y1] += 1 20 | else: 21 | a = range(x1, x2 + 1) if x1 < x2 else range(x1, x2 - 1, -1) 22 | b = range(y1, y2 + 1) if y1 < y2 else range(y1, y2 - 1, -1) 23 | for x, y in zip(a, b): 24 | d2[x, y] += 1 25 | 26 | print(sum(x > 1 for x in d.values())) 27 | print(sum(x > 1 for x in d2.values())) 28 | -------------------------------------------------------------------------------- /2021/day/6.py: -------------------------------------------------------------------------------- 1 | lanternfish = [0] * 9 2 | with open("../input/6.txt") as f: 3 | for n in f.read().split(","): 4 | lanternfish[int(n)] += 1 5 | 6 | for days_passed in range(256): 7 | fish = [lanternfish[i + 1] for i in range(8)] + [0] 8 | fish[6] += lanternfish[0] 9 | fish[8] += lanternfish[0] 10 | lanternfish = fish 11 | if days_passed == 79: 12 | print(sum(lanternfish)) 13 | 14 | print(sum(lanternfish)) 15 | -------------------------------------------------------------------------------- /2021/day/7.py: -------------------------------------------------------------------------------- 1 | with open("../input/7.txt") as f: 2 | data = list(sorted(int(n) for n in f.read().split(","))) 3 | 4 | median = data[len(data) // 2] 5 | print(sum(abs(n - median) for n in data)) 6 | 7 | mean = (sum(data) + 1) // len(data) 8 | print(sum(abs(n - mean) * (abs(n - mean) + 1) // 2 for n in data)) 9 | -------------------------------------------------------------------------------- /2021/day/8.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | 3 | with open("../input/8.txt") as f: 4 | data = f.readlines() 5 | 6 | d = { 7 | "abcefg": 0, 8 | "cf": 1, 9 | "acdeg": 2, 10 | "acdfg": 3, 11 | "bcdf": 4, 12 | "abdfg": 5, 13 | "abdefg": 6, 14 | "acf": 7, 15 | "abcdefg": 8, 16 | "abcdfg": 9, 17 | } 18 | 19 | part_1 = 0 20 | part_2 = 0 21 | for line in data: 22 | a, b = line.split(" | ") 23 | a = a.split() 24 | b = b.split() 25 | part_1 += sum(len(code) in {2, 3, 4, 7} for code in b) 26 | for permutation in permutations("abcdefg"): 27 | to = str.maketrans("abcdefg", "".join(permutation)) 28 | a_ = ["".join(sorted(code.translate(to))) for code in a] 29 | b_ = ["".join(sorted(code.translate(to))) for code in b] 30 | if all(code in d for code in a_): 31 | part_2 += int("".join(str(d[code]) for code in b_)) 32 | break 33 | 34 | print(part_1) 35 | print(part_2) 36 | -------------------------------------------------------------------------------- /2021/day/9.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | with open("../input/9.txt") as f: 4 | data = [list(map(int, line[:-1])) for line in f.readlines()] 5 | 6 | part_1 = 0 7 | basin = 0 8 | seen = {} 9 | stack = [] 10 | for r in range(len(data)): 11 | for c in range(len(data[0])): 12 | if all( 13 | r + dr < 0 14 | or r + dr >= len(data) 15 | or c + dc < 0 16 | or c + dc >= len(data[0]) 17 | or data[r][c] < data[r + dr][c + dc] 18 | for dr, dc in ((0, -1), (0, 1), (-1, 0), (1, 0)) 19 | ): 20 | part_1 += 1 + data[r][c] 21 | 22 | if (r, c) not in seen and data[r][c] != 9: 23 | stack.append((r, c)) 24 | while stack: 25 | r, c = stack.pop() 26 | for dr, dc in ((0, -1), (0, 1), (-1, 0), (1, 0)): 27 | r_ = r + dr 28 | c_ = c + dc 29 | if 0 <= r_ < len(data) and 0 <= c_ < len(data[0]): 30 | if (r_, c_) not in seen and data[r_][c_] != 9: 31 | seen[(r_, c_)] = basin 32 | stack.append((r_, c_)) 33 | basin += 1 34 | 35 | print(part_1) 36 | a, b, c = Counter(list(seen.values())).most_common(3) 37 | print(a[1] * b[1] * c[1]) 38 | -------------------------------------------------------------------------------- /2021/img/depths.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/2021/img/depths.png -------------------------------------------------------------------------------- /2021/input/11.txt: -------------------------------------------------------------------------------- 1 | 2524255331 2 | 1135625881 3 | 2838353863 4 | 1662312365 5 | 6847835825 6 | 2185684367 7 | 6874212831 8 | 5387247811 9 | 2255482875 10 | 8528557131 11 | -------------------------------------------------------------------------------- /2021/input/12.txt: -------------------------------------------------------------------------------- 1 | VJ-nx 2 | start-sv 3 | nx-UL 4 | FN-nx 5 | FN-zl 6 | end-VJ 7 | sv-hi 8 | em-VJ 9 | start-hi 10 | sv-em 11 | end-zl 12 | zl-em 13 | hi-VJ 14 | FN-em 15 | start-VJ 16 | jx-FN 17 | zl-sv 18 | FN-sv 19 | FN-hi 20 | nx-end 21 | -------------------------------------------------------------------------------- /2021/input/14.txt: -------------------------------------------------------------------------------- 1 | KOKHCCHNKKFHBKVVHNPN 2 | 3 | BN -> C 4 | OS -> K 5 | BK -> C 6 | KO -> V 7 | HF -> K 8 | PS -> B 9 | OK -> C 10 | OC -> B 11 | FH -> K 12 | NV -> F 13 | HO -> H 14 | KK -> H 15 | CV -> P 16 | SC -> C 17 | FK -> N 18 | VV -> F 19 | FN -> F 20 | KP -> O 21 | SB -> O 22 | KF -> B 23 | CH -> K 24 | VF -> K 25 | BH -> H 26 | KV -> F 27 | CO -> N 28 | PK -> N 29 | NH -> P 30 | NN -> C 31 | PP -> H 32 | SH -> N 33 | VO -> O 34 | NC -> F 35 | BC -> B 36 | HC -> H 37 | FS -> C 38 | PN -> F 39 | CK -> K 40 | CN -> V 41 | HS -> S 42 | CB -> N 43 | OF -> B 44 | OV -> K 45 | SK -> S 46 | HP -> C 47 | SN -> P 48 | SP -> B 49 | BP -> C 50 | VP -> C 51 | BS -> K 52 | FV -> F 53 | PH -> P 54 | FF -> P 55 | VK -> F 56 | BV -> S 57 | VB -> S 58 | BF -> O 59 | BB -> H 60 | OB -> B 61 | VS -> P 62 | KB -> P 63 | SF -> N 64 | PF -> S 65 | HH -> P 66 | KN -> K 67 | PC -> B 68 | NB -> O 69 | VC -> P 70 | PV -> H 71 | KH -> O 72 | OP -> O 73 | NF -> K 74 | HN -> P 75 | FC -> H 76 | PO -> B 77 | OH -> C 78 | ON -> N 79 | VN -> B 80 | VH -> F 81 | FO -> B 82 | FP -> B 83 | BO -> H 84 | CC -> P 85 | CS -> K 86 | NO -> V 87 | CF -> N 88 | PB -> H 89 | KS -> P 90 | HK -> S 91 | HB -> K 92 | HV -> O 93 | SV -> H 94 | CP -> S 95 | NP -> N 96 | FB -> B 97 | KC -> V 98 | NS -> P 99 | OO -> V 100 | SO -> O 101 | NK -> K 102 | SS -> H 103 | -------------------------------------------------------------------------------- /2021/input/16.txt: -------------------------------------------------------------------------------- 1 | C20D59802D2B0B6713C6B4D1600ACE7E3C179BFE391E546CC017F004A4F513C9D973A1B2F32C3004E6F9546D005840188C51DA298803F1863C42160068E5E37759BC4908C0109E76B00425E2C530DE40233CA9DE8022200EC618B10DC001098EF0A63910010D3843350C6D9A252805D2D7D7BAE1257FD95A6E928214B66DBE691E0E9005F7C00BC4BD22D733B0399979DA7E34A6850802809A1F9C4A947B91579C063005B001CF95B77504896A884F73D7EBB900641400E7CDFD56573E941E67EABC600B4C014C829802D400BCC9FA3A339B1C9A671005E35477200A0A551E8015591F93C8FC9E4D188018692429B0F930630070401B8A90663100021313E1C47900042A2B46C840600A580213681368726DEA008CEDAD8DD5A6181801460070801CE0068014602005A011ECA0069801C200718010C0302300AA2C02538007E2C01A100052AC00F210026AC0041492F4ADEFEF7337AAF2003AB360B23B3398F009005113B25FD004E5A32369C068C72B0C8AA804F0AE7E36519F6296D76509DE70D8C2801134F84015560034931C8044C7201F02A2A180258010D4D4E347D92AF6B35B93E6B9D7D0013B4C01D8611960E9803F0FA2145320043608C4284C4016CE802F2988D8725311B0D443700AA7A9A399EFD33CD5082484272BC9E67C984CF639A4D600BDE79EA462B5372871166AB33E001682557E5B74A0C49E25AACE76D074E7C5A6FD5CE697DC195C01993DCFC1D2A032BAA5C84C012B004C001098FD1FE2D00021B0821A45397350007F66F021291E8E4B89C118FE40180F802935CC12CD730492D5E2B180250F7401791B18CCFBBCD818007CB08A664C7373CEEF9FD05A73B98D7892402405802E000854788B91BC0010A861092124C2198023C0198880371222FC3E100662B45B8DB236C0F080172DD1C300820BCD1F4C24C8AAB0015F33D280 2 | -------------------------------------------------------------------------------- /2021/input/17.txt: -------------------------------------------------------------------------------- 1 | target area: x=29..73, y=-248..-194 2 | -------------------------------------------------------------------------------- /2021/input/21.txt: -------------------------------------------------------------------------------- 1 | Player 1 starting position: 9 2 | Player 2 starting position: 6 3 | -------------------------------------------------------------------------------- /2021/input/23.txt: -------------------------------------------------------------------------------- 1 | ############# 2 | #...........# 3 | ###D#A#C#C### 4 | #D#A#B#B# 5 | ######### 6 | -------------------------------------------------------------------------------- /2021/input/6.txt: -------------------------------------------------------------------------------- 1 | 5,1,1,3,1,1,5,1,2,1,5,2,5,1,1,1,4,1,1,5,1,1,4,1,1,1,3,5,1,1,1,1,1,1,1,1,1,4,4,4,1,1,1,1,1,4,1,1,1,1,1,5,1,1,1,4,1,1,1,1,1,3,1,1,4,1,4,1,1,2,3,1,1,1,1,4,1,2,2,1,1,1,1,1,1,3,1,1,1,1,1,2,1,1,1,1,1,1,1,4,4,1,4,2,1,1,1,1,1,4,3,1,1,1,1,2,1,1,1,2,1,1,3,1,1,1,2,1,1,1,3,1,3,1,1,1,1,1,1,1,1,1,3,1,1,1,1,3,1,1,1,1,1,1,2,1,1,2,3,1,2,1,1,4,1,1,5,3,1,1,1,2,4,1,1,2,4,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,4,3,1,2,1,2,1,5,1,2,1,1,5,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,3,1,1,5,1,1,1,1,5,1,4,1,1,1,4,1,3,4,1,4,1,1,1,1,1,1,1,1,1,3,5,1,3,1,1,1,1,4,1,5,3,1,1,1,1,1,5,1,1,1,2,2 2 | -------------------------------------------------------------------------------- /2022/day/1.py: -------------------------------------------------------------------------------- 1 | with open("../input/1.txt") as f: 2 | elfs = [sum(map(int, elf.split())) for elf in f.read().split("\n\n")] 3 | 4 | print(max(elfs)) 5 | print(sum(sorted(elfs, reverse=True)[:3])) 6 | -------------------------------------------------------------------------------- /2022/day/10.py: -------------------------------------------------------------------------------- 1 | x = 1 2 | crt = [1] 3 | with open("../input/10.txt") as f: 4 | for line in f: 5 | match line.split(): 6 | case "addx", n: 7 | crt.append(x) 8 | x += int(n) 9 | crt.append(x) 10 | 11 | print(sum(i * crt[i - 1] for i in [20, 60, 100, 140, 180, 220])) 12 | 13 | i = 0 14 | for _ in range(6): 15 | for x in range(40): 16 | if x in (crt[i] - 1, crt[i], crt[i] + 1): 17 | print("#", end="") 18 | else: 19 | print(" ", end="") 20 | i += 1 21 | print() 22 | -------------------------------------------------------------------------------- /2022/day/11.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from math import prod 3 | 4 | starting_monkeys = [] 5 | with open("../input/11.txt") as f: 6 | for chunk in f.read().strip().split("\n\n"): 7 | _, items, operation, div, true, false = chunk.split("\n") 8 | items = list(map(int, items[18:].split(","))) 9 | operation = operation[13:].replace("new", "old").replace("old", "item") 10 | div = int(div[20:]) 11 | true = int(true[28:]) 12 | false = int(false[29:]) 13 | starting_monkeys.append([items, operation, div, true, false]) 14 | 15 | product = prod(monkey[2] for monkey in starting_monkeys) 16 | 17 | for iterations in (20, 10_000): 18 | monkeys = deepcopy(starting_monkeys) 19 | score = [0] * len(starting_monkeys) 20 | for _ in range(iterations): 21 | for i, (items, operation, div, true, false) in enumerate(monkeys): 22 | for item in items: 23 | score[i] += 1 24 | exec(operation) 25 | if iterations == 20: 26 | item //= 3 27 | else: 28 | item %= product 29 | monkeys[false if item % div else true][0].append(item) 30 | monkeys[i][0] = [] 31 | 32 | print(prod(sorted(score)[-2:])) 33 | -------------------------------------------------------------------------------- /2022/day/12.py: -------------------------------------------------------------------------------- 1 | from heapq import heappush, heappop 2 | 3 | 4 | def bfs(grid, char): 5 | visit = [] 6 | seen = {} 7 | for start in grid: 8 | if grid[start] in char: 9 | heappush(visit, (0, *start)) 10 | seen[start] = 0 11 | 12 | while visit: 13 | d, x, y = heappop(visit) 14 | for dx, dy in ((0, 1), (0, -1), (1, 0), (-1, 0)): 15 | z = x + dx 16 | w = y + dy 17 | if (z, w) not in seen and (z, w) in grid: 18 | a = grid[x, y] if grid[x, y] != "S" else "a" 19 | b = grid[z, w] if grid[z, w] != "E" else "z" 20 | if ord(a) + 1 < ord(b): 21 | continue 22 | seen[z, w] = d + 1 23 | if grid[z, w] == "E": 24 | return d + 1 25 | heappush(visit, (d + 1, z, w)) 26 | 27 | 28 | with open("../input/12.txt") as f: 29 | grid = {(x, y): c for y, line in enumerate(f) for x, c in enumerate(line.strip())} 30 | 31 | print(bfs(grid, "S")) 32 | print(bfs(grid, "aS")) 33 | -------------------------------------------------------------------------------- /2022/day/14.py: -------------------------------------------------------------------------------- 1 | from itertools import pairwise 2 | from collections import defaultdict 3 | 4 | with open("../input/14.txt") as f: 5 | data = f.read().rstrip().split("\n") 6 | 7 | grid = defaultdict(lambda: ".") 8 | for line in data: 9 | arr = line.split(" -> ") 10 | for a, b in pairwise(arr): 11 | x, y = map(int, a.split(",")) 12 | z, w = map(int, b.split(",")) 13 | x, z = sorted((x, z)) 14 | y, w = sorted((y, w)) 15 | if x == z: 16 | for i in range(y, w + 1): 17 | grid[x, i] = "#" 18 | elif y == w: 19 | for i in range(x, z + 1): 20 | grid[i, y] = "#" 21 | else: 22 | print("error") 23 | 24 | lowest_point = max((y for x, y in grid)) + 2 25 | leftmost = min((x for x, y in grid)) - 1000 26 | rightmost = max((x for x, y in grid)) + 1000 27 | for x in range(leftmost, rightmost): 28 | grid[x, lowest_point] = "#" 29 | while True: 30 | sx, sy = 500, 0 31 | while sy <= lowest_point: 32 | if grid[sx, sy + 1] in "#o": 33 | if grid[sx - 1, sy + 1] not in "#o": 34 | sx -= 1 35 | elif grid[sx + 1, sy + 1] not in "#o": 36 | sx += 1 37 | else: 38 | if sx == 500 and sy == 0: 39 | print(sum(v == "o" for v in grid.values()) + 1) 40 | exit("done 1") 41 | grid[sx, sy] = "o" 42 | break 43 | sy += 1 44 | else: 45 | print(sum(v == "o" for v in grid.values())) 46 | exit("done 2") 47 | -------------------------------------------------------------------------------- /2022/day/15.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open("../input/15.txt") as f: 4 | data = f.read().strip().split("\n") 5 | 6 | ranges = [] 7 | radiuses = {} 8 | for line in data: 9 | x, y, z, w = map(int, re.findall(r"-?\d+", line)) 10 | d = abs(x - z) + abs(y - w) 11 | radiuses[x, y] = d 12 | tmp = d - abs(y - 2000000) 13 | if tmp < 0: 14 | continue 15 | intersection = tmp - x 16 | if d != abs(x - intersection) + abs(y - 2000000): 17 | intersection = x - tmp 18 | intersection_right = 2*x - intersection 19 | if intersection > x: 20 | intersection, intersection_right = intersection_right, intersection 21 | new = [] 22 | for i, (low, high) in enumerate(ranges): 23 | if intersection_right >= low and high >= intersection: 24 | intersection = min(intersection, low) 25 | intersection_right = max(intersection_right, high) 26 | else: 27 | new.append((low, high)) 28 | new.append((intersection, intersection_right)) 29 | ranges = new 30 | 31 | print(sum(high - low for low, high in ranges)) 32 | 33 | a_coeffs, b_coeffs = set(), set() 34 | for ((x, y), r) in radiuses.items(): 35 | a_coeffs.add(y - x + r + 1) 36 | a_coeffs.add(y - x - r - 1) 37 | b_coeffs.add(x + y + r + 1) 38 | b_coeffs.add(x + y - r - 1) 39 | 40 | for a in a_coeffs: 41 | for b in b_coeffs: 42 | x = (b - a) // 2 43 | y = (a + b) // 2 44 | if all(0 < c < 4000000 for c in (x, y)): 45 | if all(abs(x - x2) + abs(y - y2) > r for (x2, y2), r in radiuses.items()): 46 | print(4000000 * x + y) 47 | -------------------------------------------------------------------------------- /2022/day/18.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | with open("../input/18.txt") as f: 5 | lines = f.read().strip().split("\n") 6 | 7 | grid = set() 8 | max_x = 0 9 | max_y = 0 10 | max_z = 0 11 | for line in lines: 12 | x, y, z = map(int, line.split(",")) 13 | max_x = max(max_x, x) 14 | max_y = max(max_y, y) 15 | max_z = max(max_z, z) 16 | grid.add((x, y, z)) 17 | 18 | 19 | neighbours = [ 20 | (0, 0, 1), 21 | (0, 0, -1), 22 | (0, 1, 0), 23 | (0, -1, 0), 24 | (1, 0, 0), 25 | (-1, 0, 0), 26 | ] 27 | score = 0 28 | border = set() 29 | for x in range(-2, max_x + 2): 30 | for y in range(-2, max_y + 2): 31 | for z in range(-2, max_z + 2): 32 | if (x, y, z) not in grid: 33 | for dx, dy, dz in neighbours: 34 | if (x + dx, y + dy, z + dz) in grid: 35 | border.add((x + dx, y + dy, z + dz)) 36 | score += 1 37 | 38 | print(score) 39 | to_visit = [(-2, -2, -2)] 40 | seen = set() 41 | exterior = defaultdict(int) 42 | while to_visit: 43 | x, y, z = to_visit.pop() 44 | for dx, dy, dz in neighbours: 45 | point = (nx, ny, nz) = x + dx, y + dy, z + dz 46 | if ( 47 | nx < -2 48 | or nx > max_x + 2 49 | or ny < -2 50 | or ny > max_y + 2 51 | or nz < -2 52 | or nz > max_z + 2 53 | ): 54 | continue 55 | if point in border: 56 | exterior[point] += 1 57 | elif point not in seen: 58 | seen.add(point) 59 | to_visit.append(point) 60 | 61 | print(sum(exterior.values())) 62 | -------------------------------------------------------------------------------- /2022/day/2.py: -------------------------------------------------------------------------------- 1 | part1 = 0 2 | part2 = 0 3 | with open("../input/2.txt") as f: 4 | for line in f: 5 | a, b = line.split() 6 | a = int(a.translate(str.maketrans("ABC", "123"))) 7 | b = int(b.translate(str.maketrans("XYZ", "123"))) 8 | part1 += b + ((b - a + 1) % 3) * 3 9 | part2 += (a + b) % 3 + 1 + (b - 1) * 3 10 | 11 | print(part1) 12 | print(part2) 13 | -------------------------------------------------------------------------------- /2022/day/22.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def wrap(xy: complex, direction: complex) -> complex: 5 | zw = xy 6 | while zw in grid: 7 | zw -= pow(1j, direction) 8 | zw += pow(1j, direction) 9 | return xy if grid[zw] == "#" else zw 10 | 11 | 12 | with open("../input/22.txt") as f: 13 | m, instructions = f.read().rstrip().split("\n\n") 14 | 15 | grid = {} 16 | xy = None 17 | direction = 0 18 | for y, line in enumerate(m.split("\n"), 1): 19 | for x, c in enumerate(line, 1): 20 | if c == "#": 21 | grid[x + y * 1j] = "#" 22 | elif c == ".": 23 | grid[x + y * 1j] = "." 24 | if xy is None: 25 | xy = x + y * 1j 26 | 27 | for m in re.finditer(r"\d+", instructions): 28 | start, end = m.span() 29 | d = instructions[start - 1] 30 | n = instructions[start:end] 31 | if start != 0: 32 | direction = (direction + (1 if d == "R" else -1)) % 4 33 | for _ in range(int(n)): 34 | if xy + pow(1j, direction) not in grid: 35 | xy = wrap(xy, direction) 36 | elif grid[xy + pow(1j, direction)] == ".": 37 | xy += pow(1j, direction) 38 | elif grid[xy + pow(1j, direction)] == "#": 39 | pass 40 | 41 | print(int(1000 * xy.imag + 4 * xy.real + direction)) 42 | -------------------------------------------------------------------------------- /2022/day/25.py: -------------------------------------------------------------------------------- 1 | def f(n): 2 | if n == 0: 3 | return [] 4 | if (n % 5) == 0: 5 | return ["0"] + f(n // 5) 6 | if (n % 5) == 1: 7 | return ["1"] + f(n // 5) 8 | if (n % 5) == 2: 9 | return ["2"] + f(n // 5) 10 | if (n % 5) == 3: 11 | return ["="] + f((n + 2) // 5) 12 | if (n % 5) == 4: 13 | return ["-"] + f((n + 1) // 5) 14 | 15 | 16 | ds = {"2": 2, "1": 1, "0": 0, "-": -1, "=": -2} 17 | IN = open("../input/25.txt").read() 18 | total = 0 19 | for ln in IN.strip().split("\n"): 20 | N = 0 21 | for c in ln: 22 | N *= 5 23 | N += ds[c] 24 | 25 | total += N 26 | 27 | print("".join(f(total)[::-1])) 28 | -------------------------------------------------------------------------------- /2022/day/3.py: -------------------------------------------------------------------------------- 1 | from more_itertools import grouper 2 | 3 | 4 | def score(char: str) -> int: 5 | if char.islower(): 6 | return ord(char) - ord("a") + 1 7 | 8 | return ord(char) - ord("A") + 1 + 26 9 | 10 | 11 | with open("../input/3.txt") as f: 12 | lines = f.read().strip().split("\n") 13 | 14 | part1 = 0 15 | for line in lines: 16 | mid = len(line) // 2 17 | char = set(line[:mid]) & set(line[mid:]) 18 | part1 += score(char.pop()) 19 | 20 | part2 = 0 21 | for group in grouper(lines, 3): 22 | part2 += score(set.intersection(*map(set, group)).pop()) 23 | 24 | print(part1) 25 | print(part2) 26 | -------------------------------------------------------------------------------- /2022/day/4.py: -------------------------------------------------------------------------------- 1 | with open("../input/4.txt") as f: 2 | data = f.read().strip().split("\n") 3 | 4 | 5 | p1 = 0 6 | p2 = 0 7 | for line in data: 8 | a, b = line.split(",") 9 | x, y = map(int, a.split("-")) 10 | z, w = map(int, b.split("-")) 11 | 12 | if x >= z and y <= w or z >= x and w <= y: 13 | p1 += 1 14 | 15 | if max(x, z) <= min(y, w): 16 | p2 += 1 17 | 18 | print(p1) 19 | print(p2) 20 | -------------------------------------------------------------------------------- /2022/day/5.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import defaultdict 3 | from copy import deepcopy 4 | 5 | 6 | with open("../input/5.txt") as f: 7 | crates, moves = map(str.splitlines, f.read().rstrip().split("\n\n")) 8 | 9 | *rows, column = crates 10 | columns = defaultdict(list) 11 | for row in reversed(rows): 12 | for i, crate in enumerate(row): 13 | if crate.isupper(): 14 | columns[int(column[i])].append(crate) 15 | 16 | columns2 = deepcopy(columns) 17 | for move in moves: 18 | x, y, z = map(int, re.findall(r"\d+", move)) 19 | for i in range(x): 20 | columns[z].append(columns[y][-i - 1]) 21 | columns2[z].append(columns2[y][len(columns2[y]) - x + i]) 22 | 23 | del columns[y][-x:] 24 | del columns2[y][-x:] 25 | 26 | print("".join(columns[i].pop() for i in range(1, len(columns) + 1))) 27 | print("".join(columns2[i].pop() for i in range(1, len(columns2) + 1))) 28 | -------------------------------------------------------------------------------- /2022/day/6.py: -------------------------------------------------------------------------------- 1 | def start_of(n: int) -> int: 2 | for i in range(n, len(data)): 3 | if len(set(data[i - n + 1 : i + 1])) == n: 4 | return i + 1 5 | 6 | 7 | with open("../input/6.txt") as f: 8 | data = f.read().rstrip() 9 | 10 | print(start_of(4)) 11 | print(start_of(14)) 12 | -------------------------------------------------------------------------------- /2022/day/7.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from itertools import accumulate 3 | 4 | 5 | sizes = defaultdict(int) 6 | stack = [] 7 | with open("../input/7.txt") as f: 8 | for line in f: 9 | if line.startswith("$ ls") or line.startswith("dir"): 10 | continue 11 | 12 | match line.split(): 13 | case "$", "cd", "..": 14 | stack.pop() 15 | case "$", "cd", directory: 16 | stack.append(directory) 17 | case size, _: 18 | for path in accumulate(stack, func=lambda a, b: a + "/" + b): 19 | sizes[path] += int(size) 20 | 21 | print(sum(size for size in sizes.values() if size <= 100_000)) 22 | print(min(size for size in sizes.values() if size >= sizes["/"] - 40_000_000)) 23 | -------------------------------------------------------------------------------- /2022/day/8.py: -------------------------------------------------------------------------------- 1 | from more_itertools import before_and_after 2 | from functools import partial 3 | 4 | 5 | with open("../input/8.txt") as f: 6 | rows = [[int(c) for c in line.strip()] for line in f.readlines()] 7 | cols = list(zip(*rows)) 8 | 9 | part1 = 0 10 | for r in range(len(rows)): 11 | for c in range(len(cols)): 12 | tree = rows[r][c] 13 | part1 += ( 14 | all(x < rows[r][c] for x in rows[r][:c]) 15 | or all(x < rows[r][c] for x in rows[r][c + 1 :]) 16 | or all(x < rows[r][c] for x in cols[c][:r]) 17 | or all(x < rows[r][c] for x in cols[c][r + 1 :]) 18 | ) 19 | 20 | max_score = 0 21 | for r in range(len(rows)): 22 | for c in range(len(cols)): 23 | up = cols[c][:r][::-1] 24 | down = cols[c][r + 1 :] 25 | left = rows[r][:c][::-1] 26 | right = rows[r][c + 1 :] 27 | 28 | score = 1 29 | lower_and_higher = partial(before_and_after, lambda x: x < rows[r][c]) 30 | for row in [up, down, left, right]: 31 | lower, higher = map(len, map(list, lower_and_higher(row))) 32 | score *= lower + bool(higher) 33 | 34 | if score > max_score: 35 | max_score = score 36 | 37 | print(part1) 38 | print(max_score) 39 | -------------------------------------------------------------------------------- /2022/day/9.py: -------------------------------------------------------------------------------- 1 | from itertools import pairwise 2 | 3 | direction = {"U": -1j, "D": 1j, "L": -1, "R": 1} 4 | sign = lambda x: x and (1, -1)[x < 0] 5 | 6 | with open("../input/9.txt") as f: 7 | data = f.read().rstrip().split("\n") 8 | 9 | rope = [0] * 10 10 | part1 = set() 11 | part2 = set() 12 | for line in data: 13 | d, n = line.split() 14 | for _ in range(int(n)): 15 | rope[0] += direction[d] 16 | for H, T in pairwise(range(len(rope))): 17 | diff = rope[H] - rope[T] 18 | if abs(diff) >= 2: 19 | rope[T] += sign(diff.real) + sign(diff.imag) * 1j 20 | part1.add(rope[1]) 21 | part2.add(rope[T]) 22 | 23 | print(len(part1)) 24 | print(len(part2)) 25 | -------------------------------------------------------------------------------- /2022/input/10.txt: -------------------------------------------------------------------------------- 1 | noop 2 | noop 3 | addx 5 4 | addx 29 5 | addx -28 6 | addx 5 7 | addx -1 8 | noop 9 | noop 10 | addx 5 11 | addx 12 12 | addx -6 13 | noop 14 | addx 4 15 | addx -1 16 | addx 1 17 | addx 5 18 | addx -31 19 | addx 32 20 | addx 4 21 | addx 1 22 | noop 23 | addx -38 24 | addx 5 25 | addx 2 26 | addx 3 27 | addx -2 28 | addx 2 29 | noop 30 | addx 3 31 | addx 2 32 | addx 5 33 | addx 2 34 | addx 3 35 | noop 36 | addx 2 37 | addx 3 38 | noop 39 | addx 2 40 | addx -32 41 | addx 33 42 | addx -20 43 | addx 27 44 | addx -39 45 | addx 1 46 | noop 47 | addx 5 48 | addx 3 49 | noop 50 | addx 2 51 | addx 5 52 | noop 53 | noop 54 | addx -2 55 | addx 5 56 | addx 2 57 | addx -16 58 | addx 21 59 | addx -1 60 | addx 1 61 | noop 62 | addx 3 63 | addx 5 64 | addx -22 65 | addx 26 66 | addx -39 67 | noop 68 | addx 5 69 | addx -2 70 | addx 2 71 | addx 5 72 | addx 2 73 | addx 23 74 | noop 75 | addx -18 76 | addx 1 77 | noop 78 | noop 79 | addx 2 80 | noop 81 | noop 82 | addx 7 83 | addx 3 84 | noop 85 | addx 2 86 | addx -27 87 | addx 28 88 | addx 5 89 | addx -11 90 | addx -27 91 | noop 92 | noop 93 | addx 3 94 | addx 2 95 | addx 5 96 | addx 2 97 | addx 27 98 | addx -26 99 | addx 2 100 | addx 5 101 | addx 2 102 | addx 4 103 | addx -3 104 | addx 2 105 | addx 5 106 | addx 2 107 | addx 3 108 | addx -2 109 | addx 2 110 | noop 111 | addx -33 112 | noop 113 | noop 114 | noop 115 | noop 116 | addx 31 117 | addx -26 118 | addx 6 119 | noop 120 | noop 121 | addx -1 122 | noop 123 | addx 3 124 | addx 5 125 | addx 3 126 | noop 127 | addx -1 128 | addx 5 129 | addx 1 130 | addx -12 131 | addx 17 132 | addx -1 133 | addx 5 134 | noop 135 | noop 136 | addx 1 137 | noop 138 | noop 139 | -------------------------------------------------------------------------------- /2022/input/11.txt: -------------------------------------------------------------------------------- 1 | Monkey 0: 2 | Starting items: 99, 67, 92, 61, 83, 64, 98 3 | Operation: new = old * 17 4 | Test: divisible by 3 5 | If true: throw to monkey 4 6 | If false: throw to monkey 2 7 | 8 | Monkey 1: 9 | Starting items: 78, 74, 88, 89, 50 10 | Operation: new = old * 11 11 | Test: divisible by 5 12 | If true: throw to monkey 3 13 | If false: throw to monkey 5 14 | 15 | Monkey 2: 16 | Starting items: 98, 91 17 | Operation: new = old + 4 18 | Test: divisible by 2 19 | If true: throw to monkey 6 20 | If false: throw to monkey 4 21 | 22 | Monkey 3: 23 | Starting items: 59, 72, 94, 91, 79, 88, 94, 51 24 | Operation: new = old * old 25 | Test: divisible by 13 26 | If true: throw to monkey 0 27 | If false: throw to monkey 5 28 | 29 | Monkey 4: 30 | Starting items: 95, 72, 78 31 | Operation: new = old + 7 32 | Test: divisible by 11 33 | If true: throw to monkey 7 34 | If false: throw to monkey 6 35 | 36 | Monkey 5: 37 | Starting items: 76 38 | Operation: new = old + 8 39 | Test: divisible by 17 40 | If true: throw to monkey 0 41 | If false: throw to monkey 2 42 | 43 | Monkey 6: 44 | Starting items: 69, 60, 53, 89, 71, 88 45 | Operation: new = old + 5 46 | Test: divisible by 19 47 | If true: throw to monkey 7 48 | If false: throw to monkey 1 49 | 50 | Monkey 7: 51 | Starting items: 72, 54, 63, 80 52 | Operation: new = old + 3 53 | Test: divisible by 7 54 | If true: throw to monkey 1 55 | If false: throw to monkey 3 56 | -------------------------------------------------------------------------------- /2023/day/1.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | digits1 = {str(i): str(i) for i in range(1, 10)} 4 | digits2 = { 5 | "one": "1", 6 | "two": "2", 7 | "three": "3", 8 | "four": "4", 9 | "five": "5", 10 | "six": "6", 11 | "seven": "7", 12 | "eight": "8", 13 | "nine": "9", 14 | **digits1, 15 | } 16 | sum1 = sum2 = 0 17 | with open("../input/1.txt") as f: 18 | for line in f: 19 | digits = list(map(digits1.get, re.findall("|".join(digits1), line))) 20 | sum1 += int(digits[0] + digits[-1]) 21 | digits = list( 22 | map(digits2.get, re.findall("(?=(" + "|".join(digits2) + "))", line)) 23 | ) 24 | sum2 += int(digits[0] + digits[-1]) 25 | 26 | print(sum1) 27 | print(sum2) 28 | -------------------------------------------------------------------------------- /2023/day/11.py: -------------------------------------------------------------------------------- 1 | def expansion(present: set[int], increase: int) -> list[int]: 2 | expansions = [] 3 | empty = 0 4 | for i in range(max(present) + 1): 5 | if i not in present: 6 | empty += increase 7 | expansions.append(empty) 8 | return expansions 9 | 10 | 11 | def distance(galaxies: list[int], increase: int) -> int: 12 | r_expansion = expansion(rows, increase) 13 | c_expansion = expansion(cols, increase) 14 | 15 | distance = 0 16 | for r1, c1 in galaxies: 17 | for r2, c2 in galaxies: 18 | distance += abs(r2 + r_expansion[r2] - r1 - r_expansion[r1]) + abs(c2 + c_expansion[c2] - c1 - c_expansion[c1]) 19 | return distance // 2 20 | 21 | 22 | galaxies = [] 23 | with open("../input/11.txt") as f: 24 | rows = set() 25 | cols = set() 26 | for r, row in enumerate(f.read().strip().split("\n")): 27 | for c, char in enumerate(row): 28 | if char == "#": 29 | galaxies.append((r, c)) 30 | rows.add(r) 31 | cols.add(c) 32 | 33 | print(distance(galaxies, 1)) 34 | print(distance(galaxies, 1_000_000 - 1)) 35 | -------------------------------------------------------------------------------- /2023/day/12.py: -------------------------------------------------------------------------------- 1 | from functools import cache 2 | 3 | 4 | @cache 5 | def arrangements(springs, damaged_springs): 6 | if not damaged_springs: 7 | return 0 if springs.count("#") else 1 8 | 9 | window = damaged_springs[0] 10 | s = 0 11 | damaged = 0 12 | max_start = len(springs) 13 | for end, char in enumerate(springs): 14 | start = end - window + 1 15 | if start > max_start: 16 | break 17 | 18 | if char in "#?": 19 | damaged = min(damaged + 1, window) 20 | if char == "#" and max_start == len(springs): 21 | max_start = end 22 | else: 23 | damaged = 0 24 | 25 | next_char = "." if end + 1 == len(springs) else springs[end + 1] 26 | if damaged == window and next_char in ".?": 27 | s += arrangements(springs[end + 2:], damaged_springs[1:]) 28 | 29 | return s 30 | 31 | 32 | sum_arrangements = 0 33 | sum_arrangements2 = 0 34 | with open("../input/12.txt") as f: 35 | for line in f: 36 | springs, groups = line.split() 37 | damaged_springs = groups = tuple(map(int, groups.split(","))) 38 | sum_arrangements += arrangements(springs, damaged_springs) 39 | sum_arrangements2 += arrangements("?".join(springs for _ in range(5)), damaged_springs * 5) 40 | 41 | print(sum_arrangements) 42 | print(sum_arrangements2) 43 | -------------------------------------------------------------------------------- /2023/day/13.py: -------------------------------------------------------------------------------- 1 | def count_mirrors(arr: list[str], ignore=-1) -> int: 2 | for i in range(len(arr) - 1): 3 | c = 0 4 | while i - c >= 0 and i + c + 1 < len(arr): 5 | if arr[i - c] != arr[i + c + 1]: 6 | break 7 | c += 1 8 | else: 9 | if i + 1 == ignore: 10 | continue 11 | return i + 1 12 | return 0 13 | 14 | 15 | with open("../input/13.txt") as f: 16 | patterns = f.read().strip().split("\n\n") 17 | 18 | horizontal_mirrors = 0 19 | vertical_mirrors = 0 20 | horizontal_mirrors2 = 0 21 | vertical_mirrors2 = 0 22 | for p, pattern in enumerate(patterns): 23 | rows = list(map(list, pattern.split("\n"))) 24 | cols = list(zip(*rows)) 25 | horizontal_count = count_mirrors(rows) 26 | vertical_count = count_mirrors(cols) 27 | horizontal_mirrors += horizontal_count 28 | vertical_mirrors += vertical_count 29 | matches = set() 30 | for r, row in enumerate(rows): 31 | for c, char in enumerate(row): 32 | rows[r][c] = "#" if char == "." else "." 33 | cols = list(zip(*rows)) 34 | horizontal_count2 = count_mirrors(rows, horizontal_count) 35 | vertical_count2 = count_mirrors(cols, vertical_count) 36 | if bool(horizontal_count2) ^ bool(vertical_count2): 37 | matches.add((horizontal_count2, vertical_count2)) 38 | rows[r][c] = char 39 | a, b = matches.pop() 40 | horizontal_mirrors2 += a 41 | vertical_mirrors2 += b 42 | 43 | print(100 * horizontal_mirrors + vertical_mirrors) 44 | print(100 * horizontal_mirrors2 + vertical_mirrors2) 45 | -------------------------------------------------------------------------------- /2023/day/14.py: -------------------------------------------------------------------------------- 1 | def tilt( 2 | rocks_set: frozenset[tuple[complex, str]], 3 | d: complex, 4 | ) -> frozenset[tuple[complex, str]]: 5 | rocks = {rc: char for rc, char in rocks_set} 6 | for rc in sorted(rocks, key=lambda z: z.real * d.real if d.real else z.imag * d.imag): 7 | if rocks[rc] == "O": 8 | offset = 0 9 | while rc - offset - d in rocks and rocks[rc - offset - d] == ".": 10 | offset += d 11 | rocks[rc] = "." 12 | rocks[rc - offset] = "O" 13 | return frozenset(rocks.items()) 14 | 15 | 16 | def spin(rocks_set: frozenset[tuple[complex, str]]) -> frozenset[tuple[complex, str]]: 17 | for direction in (1, 1j, -1, -1j): 18 | rocks_set = tilt(rocks_set, direction) 19 | 20 | return rocks_set 21 | 22 | 23 | def load(rocks_set: frozenset[tuple[complex, str]]) -> int: 24 | return sum(int(max_rows - rc.real) for rc, char in rocks_set if char == "O") 25 | 26 | 27 | with open("../input/14.txt") as f: 28 | rocks_initial = frozenset( 29 | (r + c*1j, char) 30 | for r, row in enumerate(f) 31 | for c, char in enumerate(row.strip()) 32 | ) 33 | 34 | max_rows = int(max((rc.real for rc, _ in rocks_initial))) + 1 35 | print(load(tilt(rocks_initial, 1))) 36 | 37 | spins = 0 38 | spins_to_load = {} 39 | rocks_to_spins = {} 40 | rocks_set = rocks_initial 41 | while rocks_set not in rocks_to_spins: 42 | spins += 1 43 | rocks_to_spins[rocks_set] = spins 44 | rocks_set = spin(rocks_set) 45 | spins_to_load[spins] = load(rocks_set) 46 | 47 | spins = spins + 1 48 | print(spins_to_load[rocks_to_spins[rocks_set] + (1_000_000_000 - spins) % (spins - rocks_to_spins[rocks_set])]) 49 | -------------------------------------------------------------------------------- /2023/day/15.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | def hash_algorithm(label: str) -> int: 5 | hash_sum = 0 6 | for char in label: 7 | hash_sum += ord(char) 8 | hash_sum *= 17 9 | hash_sum %= 256 10 | return hash_sum 11 | 12 | 13 | with open("../input/15.txt") as f: 14 | labels = f.read().strip().split(",") 15 | 16 | print(sum(hash_algorithm(label) for label in labels)) 17 | 18 | boxes = defaultdict(dict) 19 | for i, instruction in enumerate(labels): 20 | if "-" in instruction: 21 | label = instruction[:-1] 22 | box = hash_algorithm(label) 23 | if label in boxes[box]: 24 | del boxes[box][label] 25 | else: 26 | label, focal_length = instruction.split("=") 27 | box = hash_algorithm(label) 28 | if label in boxes[box]: 29 | boxes[box][label][1] = int(focal_length) 30 | else: 31 | boxes[box][label] = [i, int(focal_length)] 32 | 33 | focusing_power = 0 34 | for box, lenses in boxes.items(): 35 | for i, (_, focal_length) in enumerate(sorted(lenses.values())): 36 | focusing_power += (box + 1) * (i + 1) * focal_length 37 | 38 | print(focusing_power) 39 | -------------------------------------------------------------------------------- /2023/day/17.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from heapq import heappop, heappush 3 | 4 | 5 | def min_heat_loss(city_blocks: dict[complex, int], min_straight: int, max_straight: int) -> int: 6 | max_row = int(max(rc.imag for rc in city_blocks)) 7 | max_col = int(max(rc.real for rc in city_blocks)) 8 | 9 | to_visit = [(0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 1)] 10 | seen = defaultdict(lambda: float("inf")) 11 | while to_visit: 12 | heat_loss, straight, rc_real, rc_imag, d_real, d_imag = heappop(to_visit) 13 | rc = rc_imag * 1j + rc_real 14 | d = d_imag * 1j + d_real 15 | if rc == max_row * 1j + max_col and straight >= min_straight: 16 | return heat_loss 17 | directions = [] 18 | if straight < max_straight: 19 | directions.append(d) 20 | if straight >= min_straight: 21 | directions.append(d * 1j) 22 | directions.append(d / 1j) 23 | 24 | for new_d in directions: 25 | new_rc = rc + new_d 26 | new_straight = straight + 1 if new_d == d else 1 27 | if new_rc in city_blocks: 28 | new_heat_loss = heat_loss + city_blocks[new_rc] 29 | if seen[new_rc, new_d, new_straight] > new_heat_loss: 30 | seen[new_rc, new_d, new_straight] = new_heat_loss 31 | heappush(to_visit, (new_heat_loss, new_straight, new_rc.real, new_rc.imag, new_d.real, new_d.imag)) 32 | 33 | 34 | with open("../input/17.txt") as f: 35 | city_blocks = { 36 | r*1j + c: int(char) 37 | for r, row in enumerate(f) 38 | for c, char in enumerate(row.strip()) 39 | } 40 | 41 | print(min_heat_loss(city_blocks, 1, 3)) 42 | print(min_heat_loss(city_blocks, 4, 10)) 43 | -------------------------------------------------------------------------------- /2023/day/2.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from collections import defaultdict 4 | 5 | possible_games = 0 6 | power = 0 7 | with open("../input/2.txt") as f: 8 | for i, line in enumerate(f): 9 | cubes = defaultdict(int) 10 | subsets = line.strip().split(": ")[1].split("; ") 11 | for subset in subsets: 12 | for cube in subset.split(", "): 13 | amount, color = cube.split(" ") 14 | cubes[color] = max(cubes[color], int(amount)) 15 | 16 | if cubes["red"] <= 12 and cubes["green"] <= 13 and cubes["blue"] <= 14: 17 | possible_games += i + 1 18 | 19 | power += cubes["red"] * cubes["green"] * cubes["blue"] 20 | 21 | print(possible_games) 22 | print(power) 23 | -------------------------------------------------------------------------------- /2023/day/3.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from collections import defaultdict 4 | 5 | with open("../input/3.txt") as f: 6 | grid = f.read().split("\n")[:-1] 7 | 8 | symbols = {} 9 | for r, row in enumerate(grid): 10 | for c, char in enumerate(row): 11 | symbols[r, c] = not char.isdigit() and char != "." 12 | 13 | sum1 = 0 14 | gears = defaultdict(list) 15 | for r, row in enumerate(grid): 16 | for n in re.finditer("\d+", row): 17 | neighbours = [ 18 | (r, c) 19 | for r in range(r - 1, r + 2) 20 | for c in range(n.start() - 1, n.end() + 1) 21 | if (r, c) in symbols and symbols[r, c] 22 | ] 23 | if neighbours: 24 | sum1 += int(n.group()) 25 | 26 | for y, x in neighbours: 27 | if grid[y][x] == "*": 28 | gears[y, x].append(int(n.group())) 29 | 30 | print(sum1) 31 | print(sum(nums[0] * nums[1] for nums in gears.values() if len(nums) == 2)) 32 | -------------------------------------------------------------------------------- /2023/day/4.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from collections import defaultdict 4 | 5 | sum1 = 0 6 | cards = defaultdict(int) 7 | with open("../input/4.txt") as f: 8 | for i, line in enumerate(f): 9 | _, win, got = re.split(":|\|", line) 10 | win = set(win.strip().split()) 11 | p = sum(n in win for n in got.strip().split()) 12 | if p: 13 | sum1 += pow(2, p - 1) 14 | for j in range(p): 15 | cards[i + 1 + j + 1] += cards[i + 1] + 1 16 | 17 | print(sum1) 18 | print(sum(cards.values()) + i + 1) 19 | -------------------------------------------------------------------------------- /2023/day/6.py: -------------------------------------------------------------------------------- 1 | from math import prod 2 | 3 | 4 | def ways(time, distance): 5 | for delta in range(time): 6 | if (time - delta) * delta > distance: 7 | break 8 | return time - 2*delta + 1 9 | 10 | 11 | with open("../input/6.txt") as f: 12 | times, distances = (line.split()[1:] for line in f.readlines()) 13 | 14 | print(prod(ways(int(t), int(d)) for t, d in zip(times, distances))) 15 | print(ways(int("".join(times)), int("".join(distances)))) 16 | -------------------------------------------------------------------------------- /2023/day/7.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | from functools import partial 3 | 4 | 5 | def score(order: str, j_as_joker: bool, hand: tuple[str, str]) -> tuple[str]: 6 | cards, _ = hand 7 | tally = [] 8 | counter = Counter(cards) 9 | if j_as_joker: 10 | jokers = counter.get('J', 0) 11 | counter['J'] = 0 12 | counter[counter.most_common(1)[0][0]] += jokers 13 | match [n for n in counter.values() if n > 1]: 14 | case [5]: 15 | tally.append(7) 16 | case [4]: 17 | tally.append(6) 18 | case [2, 3] | [3, 2]: 19 | tally.append(5) 20 | case [3]: 21 | tally.append(4) 22 | case [2, 2]: 23 | tally.append(3) 24 | case [2]: 25 | tally.append(2) 26 | case []: 27 | tally.append(1) 28 | 29 | for card in cards: 30 | tally.append(order.index(card)) 31 | 32 | return tally 33 | 34 | 35 | ordering = "123456789TJQKA" 36 | ordering2 = "J123456789TQKA" 37 | with open("../input/7.txt") as f: 38 | hands = [line.split() for line in f] 39 | 40 | hands.sort(key=partial(score, ordering, False)) 41 | print(sum((i + 1) * int(bid) for i, (_, bid) in enumerate(hands))) 42 | hands.sort(key=partial(score, ordering2, True)) 43 | print(sum((i + 1) * int(bid) for i, (_, bid) in enumerate(hands))) 44 | -------------------------------------------------------------------------------- /2023/day/8.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from itertools import cycle 4 | from math import lcm 5 | 6 | with open("../input/8.txt") as f: 7 | instructions, lines = f.read().strip().split("\n\n") 8 | 9 | commands = {} 10 | for line in lines.split("\n"): 11 | start, left, right = re.match(r"(\w+) = \((\w+), (\w+)\)", line).groups() 12 | commands[start, "L"] = left 13 | commands[start, "R"] = right 14 | 15 | node = "AAA" 16 | for steps, instruction in enumerate(cycle(instructions)): 17 | node = commands[node, instruction] 18 | if node == "ZZZ": 19 | print(steps + 1) 20 | break 21 | 22 | loop = [] 23 | for node, side in commands: 24 | if node.endswith("A") and side == "R": 25 | for steps, instruction in enumerate(cycle(instructions)): 26 | node = commands[node, instruction] 27 | if node.endswith("Z"): 28 | loop.append(steps + 1) 29 | break 30 | 31 | print(lcm(*loop)) 32 | -------------------------------------------------------------------------------- /2023/day/9.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | from itertools import pairwise 3 | 4 | s1 = 0 5 | s2 = 0 6 | with open("../input/9.txt") as f: 7 | for line in f: 8 | rows = [deque(map(int, line.split()))] 9 | while any(n != 0 for n in rows[-1]): 10 | rows.append(deque([b - a for a, b in pairwise(rows[-1])])) 11 | 12 | for i, row in enumerate(reversed(rows[1:])): 13 | rows[-i - 2].append(rows[-i - 2][-1] + row[-1]) 14 | rows[-i - 2].appendleft(rows[-i - 2][0] - row[0]) 15 | 16 | s1 += rows[0][-1] 17 | s2 += rows[0][0] 18 | 19 | print(s1) 20 | print(s2) 21 | -------------------------------------------------------------------------------- /2023/input/6.txt: -------------------------------------------------------------------------------- 1 | Time: 51 92 68 90 2 | Distance: 222 2031 1126 1225 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # advent of code 2 | 3 | ![stars](./img/stars.png) 4 | 5 | ### python only branch 6 | 7 | In **2015** I focused primarily on learning the quirks of python. 8 | Most of the code there are oneliners, sometimes even readable ones. 9 | 10 | Readability was the goal of **2016**. 11 | Achieved or not, that's for the reader to decide! 12 | 13 | **2017**, the year of nothing in particular. 14 | [Code](https://github.com/MasterMedo/aoc/blob/master/2017/day/8.py), [code](https://github.com/MasterMedo/aoc/blob/master/2017/day/18.py), [code](https://github.com/MasterMedo/aoc/blob/master/2017/day/22.py)... 15 | 16 | If you want to learn something [golfy](https://github.com/MasterMedo/aoc/blob/master/2018/day/5.py) and [quirky](https://github.com/MasterMedo/aoc/blob/master/2018/day/1.py) head over to **2018**. 17 | One liners galore, won't argue about the readability though, yuck. 18 | A cool [solution](https://github.com/MasterMedo/aoc/blob/master/2018/day/8.py) to [day 8](https://adventofcode.com/2018/day/8). 19 | 20 | **2019**, most fun year so far? 21 | Maybe because I solved all [intcode puzzles](https://adventofcode.com/2019/day/9) before starting the [mathy one](https://adventofcode.com/2019/day/22)s. 22 | 23 | If you're new to programming; **2020** is your jam. Back to the basics year with a bit of number theory. Although I managed to crack the [global leaderboard](https://adventofcode.com/2020/leaderboard/day/22) on the 90th position, my median position was 1391. 24 | 25 | **2021** was fun and games up to day 17, and a tough nut to crack from then on out. I managed to get on the leaderboard on days [5](https://adventofcode.com/2021/leaderboard/day/5) and [22](https://adventofcode.com/2021/leaderboard/day/22). My median position was 600, on 15 puzzles I was sub 300th. 26 | -------------------------------------------------------------------------------- /img/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasterMedo/aoc/6c1356a43a766fde6fefdc3031b58f6a6c3822e4/img/stars.png --------------------------------------------------------------------------------