From 71fa1a9cd36ba93bc53b942ca73d2f0e813add07 Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Mon, 13 Mar 2023 21:25:55 +0100 Subject: [PATCH] Added days 2-11 --- day02.py | 47 ++++++++++++++++++ day03.py | 80 ++++++++++++++++++++++++++++++ day04.py | 26 ++++++++++ day05.py | 11 +++++ day06.py | 44 +++++++++++++++++ day07.py | 72 +++++++++++++++++++++++++++ day08.py | 48 ++++++++++++++++++ day09.py | 15 ++++++ day10.py | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ day11.py | 85 ++++++++++++++++++++++++++++++++ 10 files changed, 574 insertions(+) create mode 100644 day02.py create mode 100644 day03.py create mode 100644 day04.py create mode 100644 day05.py create mode 100644 day06.py create mode 100644 day07.py create mode 100644 day08.py create mode 100644 day09.py create mode 100644 day10.py create mode 100644 day11.py diff --git a/day02.py b/day02.py new file mode 100644 index 0000000..ca86131 --- /dev/null +++ b/day02.py @@ -0,0 +1,47 @@ +from lib import format_main +from itertools import product +from operator import mul, add + +def primitive(operator): + def opcode(program, i): + val = lambda x: program[program[x]] + program[program[i+3]] = operator(val(i+1), val(i+2)) + return i+4 + return opcode + +opcodes = {1 : primitive(add), + 2 : primitive(mul), + 99 : lambda p, i: len(p) + } + +def interpret(program): + i = 0 + while i < len(program): + op = program[i] + i = opcodes[op](program, i) + return program + + + +def preproc(puzzle_input): + program = list(map(int, puzzle_input.split(','))) + init_prog = lambda a,b: program[:1] + [a, b] + program[3:] + return init_prog + + +def partI(init_prog): + end_state = interpret(init_prog(12, 2)) + return end_state[0] + +def partII(init_prog): + target = 19690720 + space = 2 * list(range(100)) + for noun, verb in product(space, space): + memory = init_prog(noun, verb) + end_state = interpret(memory) + if end_state[0] == target: + break + + return 100*noun + verb + +import solver diff --git a/day03.py b/day03.py new file mode 100644 index 0000000..b05468e --- /dev/null +++ b/day03.py @@ -0,0 +1,80 @@ +up = lambda v: (v[0], v[1] + 1) +down = lambda v: (v[0], v[1] - 1) +left = lambda v: (v[0] - 1, v[1]) +right = lambda v: (v[0] + 1, v[1]) + +moves = {'U' : up, + 'D' : down, + 'L' : left, + 'R' : right + } + +def memoize(f): + cache = dict() + def memf(path): + if path not in cache: + cache[path] = f(path) + return cache[path] + return memf + +def iterate(f, x, N): + for i in range(N): + yield x + x = f(x) + +@memoize +def lines(path): + pos = (0, 0) + r = [] + for move in path.split(','): + dir, steps = move[0], int(move[1:]) + line = list(iterate(moves[dir], pos, steps+1)) + r.append(line) + pos = line[-1] + return r + +def coordinates(path, corners=True): + return sum((line[1:len(line) - 1 + corners] + for line in lines(path)), []) + +def crossings(*paths): + return set.intersection(*(set(coordinates(path, corners=False)) + for path in paths)) + +def min_crossing(path1, path2, f): + return min(f(v) for v in crossings(path1, path2)) + +def preproc(puzzle_input): + return puzzle_input.split() + +def partI(paths): + key = lambda v: abs(v[0]) + abs(v[1]) + + path1, path2 = paths + return min_crossing(path1, path2, key) + +def partII(paths): + path1, path2 = paths + def key(c1, c2): + r = lambda v: c1.index(v) + c2.index(v) + 2 + return r + + def min_steps(p1, p2): + c1, c2 = coordinates(p1), coordinates(p2) + return min_crossing(p1, p2, key(c1, c2)) + + return min_steps(path1, path2) + +import solver + +tests = solver.Tests() +tests.add("R75,D30,R83,U83,L12,D49,R71,U7,L72\n" + + "U62,R66,U55,R34,D71,R55,D58,R83", + partI=159, + partII=610) + +tests.add("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\n" + + "U98,R91,D20,R16,D67,R40,U7,R15,U6,R7", + partI=135, + partII=410) + diff --git a/day04.py b/day04.py new file mode 100644 index 0000000..9f785b3 --- /dev/null +++ b/day04.py @@ -0,0 +1,26 @@ + + +def preproc(puzzle_input): + space = tuple(map(int, puzzle_input.split('-'))) + cands = [] + for i in range(*space): + digs = str(i) + + if sorted(digs) != list(digs): + continue + if max(digs.count(d) for d in set(digs)) < 2: + continue + cands.append(i) + return cands + +def partI(cands): + return len(cands) + +def partII(cands): + c = 0 + for i in cands: + digs = str(i) + if 2 in [digs.count(d) for d in set(digs)]: + c += 1 + return c + diff --git a/day05.py b/day05.py new file mode 100644 index 0000000..27f676f --- /dev/null +++ b/day05.py @@ -0,0 +1,11 @@ +from intcode import Interpreter, SingletonIO + +def preproc(puzzle_input): + return list(map(int, puzzle_input.split(','))) + +def partI(program): + return Interpreter(program, SingletonIO).run(1) + +def partII(program): + return Interpreter(program, SingletonIO).run(5) + diff --git a/day06.py b/day06.py new file mode 100644 index 0000000..98afb87 --- /dev/null +++ b/day06.py @@ -0,0 +1,44 @@ +from lib import Graph + +def preproc(puzzle_input): + graph = Graph() + for line in puzzle_input.split('\n'): + sun, planet = line.split(')') + graph.add_edge(sun, planet) + return graph + +def partI(graph): + return sum(w for node, w in graph.min_paths("COM").items()) + +def partII(graph): + return graph.min_path("SAN", "YOU") - 2 + +import solver + +tests = solver.Tests() +tests.add("""COM)B +B)C +C)D +D)E +E)F +B)G +G)H +D)I +E)J +J)K +K)L""", partI=42) + +tests.add("""COM)B +B)C +C)D +D)E +E)F +B)G +G)H +D)I +E)J +J)K +K)L +K)YOU +I)SAN""", partII=4) + diff --git a/day07.py b/day07.py new file mode 100644 index 0000000..b823eff --- /dev/null +++ b/day07.py @@ -0,0 +1,72 @@ +from lib import format_main +from intcode import Interpreter, makeIO, Singleton +from itertools import permutations + +stack_size = 5 +fst_amp_input = 0 + +IO = makeIO(list, Singleton) + +def preproc(puzzle_input): + program = list(map(int, puzzle_input.split(','))) + amp = lambda : Interpreter(program, IO) + return amp + + + +def partI(amp): + phase_range = range(stack_size) + best = 0 + + for perm in permutations(phase_range): + amp_in = fst_amp_input + for phase in perm: + amp_in = amp().run([phase, amp_in]) + best = max(amp_in, best) + return best + +def partII(amp): + phase_range = range(5, 10) + best = 0 + + for perm in permutations(phase_range): + amps = [amp() for _ in range(stack_size)] + for p, a in zip(perm, amps): + a.write([p]) + next(a) + + amp_in = fst_amp_input + while True: + try: + for a in amps: + a.write([amp_in]) + amp_in = next(a) + except StopIteration: + break + best = max(amp_in, best) + + return best + +import solver + +tests = solver.Tests() + +tests.add( + "3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0", partI=43210) + +tests.add( + "3,23,3,24,1002,24,10,24,1002,23,-1,23," + + "101,5,23,23,1,24,23,23,4,23,99,0,0", partI=54321) + +tests.add( + "3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33," + + "1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0", partI=65210) + +tests.add( + "3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26," + + "27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5", partII=139629729) + +tests.add( + "3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54," + + "-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4," + + "53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10", partII=18216) diff --git a/day08.py b/day08.py new file mode 100644 index 0000000..b12bec1 --- /dev/null +++ b/day08.py @@ -0,0 +1,48 @@ + +ZERO, ONE, TWO = "012" + +BLACK = 0 +WHITE = 1 + +color = {WHITE : u"\u2B1C", + BLACK : u"\u2B1B" + } + + +class Image: + def __init__(self, data, w, h): + self.data = data + self.w = w + self.h = h + + def layers(self): + w, h = self.w, self.h + return (self.data[i:i+w*h] for i in range(0, len(self.data), w*h)) + + def image(self): + final = str() + for stack in zip(*self.layers()): + final += (''.join(stack).replace(TWO, "") + TWO)[0] + return final + + def __repr__(self): + w, image = self.w, self.image() + return '\n'.join(image[i:i+w] for i in range(0, len(image), w)) + + def __str__(self): + return repr(self).replace(ZERO, color[BLACK]).replace(ONE, color[WHITE]) + + + +def preproc(puzzle_input): + w, h = 25, 6 + data = puzzle_input.replace('\n', '') + return Image(data, w, h) + +def partI(image): + layer = min(image.layers(), key=lambda ly: ly.count(ZERO)) + return layer.count(ONE) * layer.count(TWO) + +def partII(image): + return '\n' + str(image) + diff --git a/day09.py b/day09.py new file mode 100644 index 0000000..40b30c1 --- /dev/null +++ b/day09.py @@ -0,0 +1,15 @@ +from intcode import Interpreter, SingletonIO + +def preproc(puzzle_input): + return list(map(int, puzzle_input.split(','))) + +def partI(program): + return Interpreter(program, SingletonIO).run(1) + +def partII(program): + return Interpreter(program, SingletonIO).run(2) + +import solver + +tests = solver.Tests() +tests.add("104,1125899906842624,99", partI=1125899906842624) diff --git a/day10.py b/day10.py new file mode 100644 index 0000000..4f1abd5 --- /dev/null +++ b/day10.py @@ -0,0 +1,146 @@ +from fractions import gcd, Fraction +from itertools import product +from functools import total_ordering +from collections import defaultdict + +ASTEROID = '#' + +def zrange(x, y, step): + if x == y == step == 0: + def yzero(): + while True: + yield 0 + return yzero() + return range(x, y, step) + +def angle(v): + if v.x == 0: + return (2 * int(v.y > 0), 0) + halve = 1 if v.x > 0 else 3 + return (halve, Fraction(v.y, v.x)) + +def rebase(base, vectors): + return (v - base for v in vectors if v != base) + +@total_ordering +class Vector: + def __init__(self, x, y): + self.x = x + self.y = y + def __add__(self, other): + return Vector(self.x + other.x, self.y + other.y) + def __sub__(self, other): + return self + Vector(-other.x, -other.y) + def __eq__(self, other): + return self.x == other.x and self.y == other.y + def __lt__(self, other): + return (self.x**2 + self.y**2) < (other.x**2 + other.y**2) + def __str__(self): + return str((self.x, self.y)) + def __repr__(self): + return str(self) + +class Map: + def __init__(self, map): + self.map = map + + def __getitem__(self, v): + return self.map[v.y][v.x] + + def __str__(self): + return '\n'.join(self.map) + + def is_asteroid(self, v): + return self[v] == ASTEROID + + def vectors(self): + X, Y = len(self.map[0]), len(self.map) + return (Vector(x, y) for x, y in product(range(X), range(Y))) + + def asteroid_vectors(self): + return filter(lambda v: self.is_asteroid(v), self.vectors()) + + def num_in_sight(self, v): + vs = rebase(v, self.asteroid_vectors()) + return len(set(map(angle, vs))) + + def best(self): + return max((self.num_in_sight(v), v) for v in self.asteroid_vectors()) + + def vaporize_seq(self, base): + vs = rebase(base, self.asteroid_vectors()) + angles = defaultdict(list) + for v in vs: + angles[angle(v)].append(v) + for ang in angles.keys(): + angles[ang].sort() + r = [] + for i in range(max(map(len, angles.values()))): + r += [angles[ang][i] + base + for ang in sorted(angles.keys()) if i < len(angles[ang])] + return r + +def preproc(puzzle_input): + asteroid_map = Map(puzzle_input.split()) + score, asteroid = asteroid_map.best() + return asteroid_map, asteroid, score + +def partI(packed): + _, _, score = packed + return score + +def partII(packed): + asteroid_map, asteroid, _ = packed + v = asteroid_map.vaporize_seq(asteroid)[199] + return 100*v.x + v.y + +import solver + +tests = solver.Tests() + +map1 = \ +""".#..# +..... +##### +....# +...##""" + +map2 = \ +"""#.#...#.#. +.###....#. +.#....#... +##.#.#.#.# +....#.#.#. +.##..###.# +..#...##.. +..##....## +......#... +.####.###. +""" + +map3 = \ +""".#..##.###...####### +##.############..##. +.#.######.########.# +.###.#######.####.#. +#####.##.#.##.###.## +..#####..#.######### +#################### +#.####....###.#.#.## +##.################# +#####.##.###..####.. +..######..##.####### +####.##.####...##..# +.#####..#.######.### +##...#.##########... +#.##########.####### +.####.#.###.###.#.## +....##.##.###..##### +.#.#.###########.### +#.#.#.#####.####.### +###.##.####.##.#..## +""" + +tests.add(map1, partI=8) +tests.add(map2, partI=35) +tests.add(map3, partI=210, partII=802) diff --git a/day11.py b/day11.py new file mode 100644 index 0000000..c433cb9 --- /dev/null +++ b/day11.py @@ -0,0 +1,85 @@ +from advent import read_input +from intcode import Interpreter +from collections import defaultdict + +BLACK = 0 +WHITE = 1 + +color = {WHITE : u"\u2B1C", + BLACK : u"\u2B1B" + } + +UP = (0, 1) +LEFT = 0 +RIGHT = 1 + +def rotate(v, dir): + return (-dir) * v[1], dir * v[0] + +def left(v): + return rotate(v, 1) + +def right(v): + return rotate(v, -1) + +def add(v1, v2): + return v1[0] + v2[0], v1[1] + v2[1] + +class Canvas(defaultdict): + def __init__(self, color): + self.color = color + super(Canvas, self).__init__(int) + + def __str__(self): + xs, ys = zip(*self.keys()) + return '\n'.join(''.join(self.color[self[(x, y)]] + for x in range(min(xs), max(xs)+1)) + for y in range(max(ys), min(ys)-1, -1)) + + def __repr__(self): + return unicode(self).encode("utf-8") + + +class robotIO: + def __init__(self, canvas=Canvas(color)): + self.canvas = canvas + self.dir = UP + self.pos = 0, 0 + self.paint = True + + def pop_input(self): + return self.canvas[self.pos] + + def append_output(self, x): + if self.paint: + self.canvas[self.pos] = x + else: + self.dir = left(self.dir) if x == LEFT else right(self.dir) + self.pos = add(self.pos, self.dir) + self.paint = not self.paint + + def flush(self): + return self.canvas + +class Robot: + def __init__(self, program, canvas=Canvas(color)): + self.canvas = canvas + self.program = program + + def paint(self): + comp = Interpreter(self.program, robotIO) + comp.IO.canvas = self.canvas + return comp.run() + +def preproc(puzzle_input): + return list(map(int, puzzle_input.split(','))) + +def partI(program): + canvas = Robot(program).paint() + return len(canvas) + +def partII(program): + canvas = Canvas(color) + canvas[(0, 0)] = WHITE + canvas = Robot(program, canvas).paint() + return '\n' + str(canvas)