from collections import deque from vm import VM, read_program ns = read_program(21) def run(inputs): for output in VM(ns, deque(map(ord, inputs))): pass return output # Part one # We want to jump if there is land in four steps, but a hole # in one of the next three steps, i.e. # J = D AND ((NOT A) OR (NOT B) OR (NOT C)) inputs = """NOT A T NOT B J OR T J NOT C T OR T J AND D J WALK """ print(run(inputs)) # Part two # We now want to also ensure that there is land at either # 5 steps or 8 steps, i.e. something like # J = D AND ((NOT A) OR (NOT B) OR (NOT C)) AND (H OR E)
from collections import deque from itertools import cycle, permutations from math import inf from vm import VM, read_program p07 = read_program(7) # Part one m = -inf for perm in permutations(range(5)): vms = [] signal = 0 for phase in perm: vm = VM(p07) signal = next(VM(p07, deque([phase, signal]))) m = max(m, signal) print(m) # Part two m = -inf for perm in permutations(range(5, 10)): vms = [VM(p07, deque([phase])) for phase in perm] signal = 0 try: for i in cycle(range(5)): vms[i].inputs.append(signal) signal = next(vms[i]) except StopIteration: m = max(m, signal) print(m)
from collections import deque import networkx as nx from vm import VM, read_program ns = read_program(15) q = deque() vm = VM(ns) q.append((0, vm)) direction = {1: 1j, 2: -1j, 3: -1, 4: 1} G = nx.Graph() while q: loc, base_vm = q.pop() for d in range(1, 5): vm = base_vm.clone() vm.inputs = deque([d]) output = next(vm) if output: new_loc = loc + direction[d] if new_loc not in G.nodes: if output == 2: oxygen = new_loc q.append((new_loc, vm)) G.add_edge(loc, new_loc) # Part one print(nx.shortest_path_length(G, 0, oxygen))
from collections import deque from vm import VM, read_program p05 = read_program(5) # Part one vm = VM(p05, deque([1])) print(vm.run_until_next_nonzero_output()) # Part two vm = VM(p05, deque([5])) print(next(vm))
from collections import deque from itertools import chain, combinations import sys from vm import VM, read_program ns = read_program(25) # We first play the actual game to figure out what items exist and where # the locked door is; to play the game, run `python -m day25.solutions -i` if len(sys.argv) > 1 and sys.argv[1] == '-i': inputs = deque([]) vm = VM(ns, inputs) while True: o = next(vm.it) if o is not None: print(chr(o), end='') elif not inputs: inp = input() + '\n' for c in map(ord, inp): inputs.append(c) # Now, loop over all possible combinations of items to drop. If we are neither # too heavy or too light, that means we're done. def powerset(iterable): s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) items = ['spool of cat6', 'asterisk', 'jam', 'shell', 'astronaut ice cream', 'space heater',
from collections import defaultdict, deque from vm import VM, read_program ns = read_program(11) def get_colors(initial): inputs = deque() vm = VM(ns, inputs) d = -1j loc = 0 colors = defaultdict(int) colors[0] = initial try: while True: inputs.append(colors[loc]) colors[loc] = next(vm) d *= 1j if next(vm) else -1j loc += d except StopIteration: return colors # Part one print(len(get_colors(0))) # Part two c = get_colors(1) reals = set(int(z.real) for z in c) imags = set(int(z.imag) for z in c)
from collections import defaultdict, deque from queue import Queue import time from vm import VM, read_program ns = read_program(23) class Input: def __init__(self, i): self.inputs = deque([i]) def popleft(self): return self.inputs.popleft() if self.inputs else -1 def add(self, val): self.inputs.append(val) vms = [] for i in range(50): inputs = Input(i) vm = VM(ns, inputs) vms.append(vm) i = 0 idling = set() NAT = None last_y = None while True: dst = next(vms[i].it) if dst is None:
from collections import deque from itertools import count from vm import VM, read_program ns = read_program(19) # Part one print(sum(next(VM(ns, deque([x, y]))) for x in range(50) for y in range(50))) # A quick glance at the output suggest that the relevant y coordinate # is at least 500, so we start our search there to avoid some edge # cases near the origin def solve(): prev_first_x = 0 rows = [] for y in count(500): first_x = None if prev_first_x == None: prev_first_x = 0 x = prev_first_x while True: inputs = deque([x, y]) vm = VM(ns, inputs) output = next(vm) if output: if first_x == None: first_x = x if rows: x = rows[-1][1] - 1
from collections import deque from vm import VM, read_program p09 = read_program(9) # Part one vm = VM(p09, deque([1])) print(next(vm)) # Part two vm = VM(p09, deque([2])) print(next(vm))
import numpy as np from vm import VM, read_program ns = read_program(13) # Part one vm = VM(ns) print(sum(t == 2 for _, _, t in zip(vm, vm, vm))) # Part two paddle_x = 0 ball_x = 0 class AI: @staticmethod def popleft(): return np.sign(ball_x - paddle_x) vm = VM(ns, AI) vm[0] = 2 try: while True: x, y, tile_id = next(vm), next(vm), next(vm) if x == -1 and y == 0: score = tile_id elif tile_id == 3: paddle_x = x elif tile_id == 4:
from collections import deque from vm import VM, read_program ns = read_program(17) # Part one vm = VM(ns) x = 0 y = 0 scaffolds = set() field = {} for output in vm: field[y + x * 1j] = output if output == 35: scaffolds.add(y + x * 1j) if output == 10: y += 1 x = 0 else: x += 1 print( sum(x.real * x.imag for x in scaffolds if x + 1 in scaffolds and x - 1 in scaffolds and x + 1j in scaffolds and x - 1j in scaffolds)) # Part two # We first take a look at the map and based on that, manually # determine what the routines must look like. max_x = int(max(z.real for z in scaffolds)) max_y = int(max(z.imag for z in scaffolds))