def try_combos(combo, memory, input=0): progs = init_programs(combo, memory) while True: output = list(chain_progs(progs, input)) if len(output) > 0: input = output[-1] if len(output) < len(combo): return input def part1(filename): memory = load_memory(filename, script=__file__) return max( try_combos_once(perm, memory) for perm in permutations(list(range(5)))) def part2(filename): memory = load_memory(filename, script=__file__) return max( try_combos(perm, memory) for perm in permutations(list(range(5, 10)))) if __name__ == "__main__": test(43210, part1('input-test-1.txt')) test(54321, part1('input-test-2.txt')) test(65210, part1('input-test-3.txt')) test(24625, part1('input.txt')) test(139629729, part2('input-test-4.txt')) test(18216, part2('input-test-5.txt')) test(36497698, part2('input.txt'))
def part1(filename): return sum(find_numbers(load_json(filename))) def part2(filename): return sum(find_numbers(load_json(filename), ignore="red")) # def part2(filename): # data = load_custom(filename) # return None if __name__ == "__main__": test(6, part1('input-test-1.txt')) test(6, part1('input-test-2.txt')) test(3, part1('input-test-3.txt')) test(3, part1('input-test-4.txt')) test(0, part1('input-test-5.txt')) test(0, part1('input-test-6.txt')) test(0, part1('input-test-7.txt')) test(0, part1('input-test-8.txt')) test(191164, part1('input.txt')) test(6, part2('input-test-1.txt')) test(4, part2('input-test-9.txt')) test(0, part2('input-test-10.txt')) test(6, part2('input-test-11.txt')) test(87842, part2('input.txt'))
from day01.main import load, test def load_strings(filename, script=__file__): return load(filename, script=script) def part1(filename): strings = load_strings(filename) return sum(len(string) - len(eval(string)) for string in strings) def part2(filename): strings = load_strings(filename) return sum(len(json.dumps(string)) - len(string) for string in strings) if __name__ == "__main__": test(2, part1('input-test-1.txt')) test(2, part1('input-test-2.txt')) test(3, part1('input-test-3.txt')) test(5, part1('input-test-4.txt')) test(1350, part1('input.txt')) test(4, part2('input-test-1.txt')) test(4, part2('input-test-2.txt')) test(6, part2('input-test-3.txt')) test(5, part2('input-test-4.txt')) test(2085, part2('input.txt'))
cup.right = (c := (b := (a := cup.right).right).right).right while val in {a.val, b.val, c.val}: val = decrement(val) dest = lookup[val] dest.right, c.right, cup = a, dest.right, cup.right cup = lookup[1] while (cup := cup.right): yield cup.val def part1(filename, moves): digits = load_digits(filename) return int(''.join( map(str, islice(cup_game(digits, moves), len(digits) - 1)))) def part2(filename, moves): digits = load_digits(filename) + list(range(10, 1000001)) return prod(islice(cup_game(digits, moves), 2)) if __name__ == "__main__": test(92658374, part1('input-test-1.txt', 10)) test(67384529, part1('input-test-1.txt', 100)) test(49725386, part1('input.txt', 100)) test(149245887792, part2('input-test-1.txt', 10000000)) test(538935646702, part2('input.txt', 10000000))
def get_diffs(nums): return (b - a for a, b in zip([0] + nums, nums + [nums[-1] + 3])) def part1(filename): nums = sorted(load_ints(filename, script=__file__)) return prod(Counter(get_diffs(nums)).values()) @cache def fib(n, order): return sum(fib(n - i, order) for i in range(1, order + 1)) if n > 0 else n == 0 def part2(filename): nums = sorted(load_ints(filename, script=__file__)) return prod(diff == 3 or fib(len(list(parts)), 3) for diff, parts in groupby(get_diffs(nums))) if __name__ == "__main__": test(35, part1('input-test-1.txt')) test(220, part1('input-test-2.txt')) test(1656, part1('input.txt')) test(8, part2('input-test-1.txt')) test(19208, part2('input-test-2.txt')) test(56693912375296, part2('input.txt'))
return {(x, y): next(layer[y][x] for layer in layers if layer[y][x] != 2) for y in range(h) for x in range(w)}, w, h def image_to_str(image, w, h): return print2d(image, w, h, translate=lambda val: ' *'[val]) def part1(filename, w, h): return checksum(load_layers(filename, w, h)[0]) def part2(filename, w, h): return image_to_str(*merge_layers(*load_layers(filename, w, h))) if __name__ == "__main__": test(1, part1('input-test-1.txt', 3, 2)) test(2806, part1('input.txt', 25, 6)) test(" *\n* ", part2('input-test-2.txt', 2, 2)) expected = """\ **** *** ** ** *** * * * * * * * * * *** * * * *** * * * * **** * * * * * * * * * * * **** *** ** * * *** \ """ test(expected, part2('input.txt', 25, 6))
return min(search(), default=0) def part1(filename): grid = load_grid(filename) return CollectKeys(grid).distance_to_collect_keys() def part2(filename): grid = load_grid(filename) x, y = next((x, y) for x, y in grid if grid[x, y] == '@') for dy, row in enumerate(['1#2', '###', '3#4'], -1): for dx, ch in enumerate(row, -1): grid[x + dx, y + dy] = ch return CollectKeys(grid).distance_to_collect_keys() if __name__ == "__main__": test(8, part1('input-test-1.txt')) test(86, part1('input-test-2.txt')) test(132, part1('input-test-3.txt')) test(136, part1('input-test-4.txt')) test(81, part1('input-test-5.txt')) test(4544, part1('input.txt')) test(8, part2('input-test-6.txt')) test(24, part2('input-test-7.txt')) test(32, part2('input-test-8.txt')) test(72, part2('input-test-9.txt')) test(1692, part2('input.txt'))
dfs([], self.get_output()) for d in rooms[SECURITY]['path']: self.go(d) end_direction = next(d for d, name in rooms[SECURITY]['doors'].items() if name == SECURITY) carrying = set(usable_items) for b in range(2**len(usable_items)): for i, item in enumerate(usable_items): if (1 << i) & b: if item not in carrying: self.manipulate('take', item) carrying.add(item) else: if item in carrying: self.manipulate('drop', item) carrying.remove(item) title, _, _, messages = self.parse_output(self.go(end_direction)) if title != SECURITY: return int(messages[2].split(' ')[11]) def solve(filename): memory = load_memory(filename, script=__file__) game = Game(memory) return game.solve() if __name__ == "__main__": test(537002052, solve('input.txt'))
def has_exactly_n(iterable, n): return n in Counter(iterable).values() def solve(filename, extra_check): start, end = map(int, load(filename, script=__file__)[0].split('-', 2)) return sum( is_sorted(s) and extra_check(s, 2) for s in map(str, range(start, end + 1))) def part1(filename): return solve(filename, has_at_least_n) def part2(filename): return solve(filename, has_exactly_n) if __name__ == "__main__": test(1, part1('input-test-1.txt')) test(0, part1('input-test-2.txt')) test(0, part1('input-test-3.txt')) test(1605, part1('input.txt')) test(1, part2('input-test-4.txt')) test(0, part2('input-test-5.txt')) test(1, part2('input-test-6.txt')) test(1102, part2('input.txt'))
from hashlib import md5 from day01.main import load, test def load_secret(filename, script=__file__): return load(filename, script=script)[0] def str_to_md5(s): return md5(s.encode()).hexdigest() def advent_md5s(secret): for i in count(1): yield i, str_to_md5(secret + str(i)) def solve(filename, n): secret = load_secret(filename) return next(i for i, hex in advent_md5s(secret) if hex[:n] == "0" * n) def part1(filename): return solve(filename, 5) def part2(filename): return solve(filename, 6) if __name__== "__main__": test(609043, part1('input-test-1.txt')) test(1048970, part1('input-test-2.txt')) test(254575, part1('input.txt')) test(1038736, part2('input.txt'))
dx, dy = dx + amt * dx2, dy + amt * dy2 else: x, y = x + amt * dx2, y + amt * dy2 elif dn == 'L': for _ in range(0, amt, 90): dx, dy = dy, -dx elif dn == 'R': for _ in range(0, amt, 90): dx, dy = -dy, dx elif dn == 'F': x, y = x + amt * dx, y + amt * dy return abs(x) + abs(y) def part1(filename): dirs = load_dirs(filename) return navigate(dirs, False, 1, 0) def part2(filename): dirs = load_dirs(filename) return navigate(dirs, True, 10, -1) if __name__ == "__main__": test(25, part1('input-test-1.txt')) test(858, part1('input.txt')) test(286, part2('input-test-1.txt')) test(39140, part2('input.txt'))
def search_all(string, regexes): return all(bool(re.search(regex, string)) for regex in regexes) def solve(filename, regexes): strings = load_strings(filename) return sum(search_all(s, regexes) for s in strings) def part1(filename): return solve(filename, nice_regexes['v1']) def part2(filename): return solve(filename, nice_regexes['v2']) if __name__ == "__main__": test(1, part1('input-test-1.txt')) test(1, part1('input-test-2.txt')) test(0, part1('input-test-3.txt')) test(0, part1('input-test-4.txt')) test(0, part1('input-test-5.txt')) test(255, part1('input.txt')) test(1, part2('input-test-6.txt')) test(1, part2('input-test-7.txt')) test(0, part2('input-test-8.txt')) test(0, part2('input-test-9.txt')) test(55, part2('input.txt'))
for line in load(filename, script=script) ] def load_passwords(filename, script=__file__): regex = r'^(\d+)-(\d+) (\w): (\w+)$' return [(int(start), int(end), letter, password) for start, end, letter, password in load_regex(filename, regex=regex, script=__file__)] def part1(filename): P = load_passwords(filename) return sum(start <= Counter(password)[letter] <= end for start, end, letter, password in P) def part2(filename): P = load_passwords(filename) return sum( sum( int(x - 1 < len(password) and password[x - 1] == letter) for x in (start, end)) % 2 for start, end, letter, password in P) if __name__ == "__main__": test(2, part1('input-test-1.txt')) test(638, part1('input.txt')) test(1, part2('input-test-1.txt')) test(699, part2('input.txt'))
if mode == 1 or override: vals.append(val + adjust) else: vals.append(self.memory[adjust + val]) modes //= 10 self.pos += 1 return vals def run_computer(self, ops=default_ops): while self.pos < len(self.memory) and not self.interrupt: modes, opcode = divmod(self.memory[self.pos], 100) if opcode == 99: return self.pos += 1 output = ops[opcode](self, modes) if output is not None: yield output def part1(filename): memory = load_memory(filename, script=__file__) return list(Program(memory, [1]).run_computer())[-1] def part2(filename): memory = load_memory(filename, script=__file__) return list(Program(memory, [5]).run_computer())[-1] if __name__ == "__main__": test(13787043, part1("input.txt")) test(3892695, part2("input.txt"))
dx, dy = q.popleft() multiple = targets[dx, dy].pop() yield x + dx * multiple, y + dy * multiple if targets[dx, dy]: q.append((dx, dy)) def part1(filename): astroids = astroid_visibility(load_grid(filename)) x, y = starting_astroid(astroids) return (x, y), len(astroids[x, y]) def part2(filename, index): astroids = astroid_visibility(load_grid(filename)) x, y = starting_astroid(astroids) return next_nth(target_astroids(astroids, x, y), index) if __name__ == "__main__": test(((3, 4), 8), part1('input-test-1.txt')) test(((5, 8), 33), part1('input-test-2.txt')) test(((1, 2), 35), part1('input-test-3.txt')) test(((6, 3), 41), part1('input-test-4.txt')) test(((11, 13), 210), part1('input-test-5.txt')) test(((8, 3), 30), part1('input-test-6.txt')) test(((27, 19), 314), part1('input.txt')) test((14, 3), part2('input-test-6.txt', 35)) test((8, 2), part2('input-test-5.txt', 199)) test((15, 13), part2('input.txt', 199))
yield x, y for step in steps: dx, dy = arrows[step] x, y = x + dx, y + dy yield x, y def part1(filename): steps = load_steps(filename) return len(set(follow(steps))) def part2(filename): steps = load_steps(filename) return len( set( chain(follow(islice(steps, 0, None, 2)), follow(islice(steps, 1, None, 2))))) if __name__ == "__main__": test(2, part1('input-test-1.txt')) test(4, part1('input-test-2.txt')) test(2, part1('input-test-3.txt')) test(2565, part1('input.txt')) test(3, part2('input-test-4.txt')) test(3, part2('input-test-2.txt')) test(11, part2('input-test-3.txt')) test(2639, part2('input.txt'))
def setup_tiles(paths): tiles = defaultdict(lambda: -1) for path in paths: tiles[tuple(map(sum, zip(*(COMPASS[step] for step in path))))] *= -1 return {a for a, b in tiles.items() if b == 1} def simulate(paths, steps): tiles = setup_tiles(paths) for _ in range(steps): tiles = set(simulate_step(tiles, COMPASS.values(), [{2}, {1, 2}])) return len(tiles) def part1(filename): return simulate(load_paths(filename), 0) def part2(filename): return simulate(load_paths(filename), 100) if __name__ == "__main__": test(10, part1('input-test-1.txt')) test(473, part1('input.txt')) test(2208, part2('input-test-1.txt')) test(4070, part2('input.txt'))
def is_valid(password): return any(ord(a) == ord(b) - 1 == ord(c) - 2 for a, b, c in zip(password, password[1:], password[2:])) \ and bool(re.search(r'(.)\1.*(.)\2', password)) \ and not re.search(r'[iol]', password) def next_password(password): if password[-1] == 'z': return next_password(password[:-1]) + 'a' add = 2 if password[-1] == 'h' or password[-1] == 'n' or password[ -1] == 'k' else 1 return password[:-1] + chr(ord(password[-1]) + add) def valid_passwords(password): while True: password = next_password(password) if is_valid(password): yield password if __name__ == "__main__": test(False, is_valid("hijklmmn")) test(False, is_valid("abbceffg")) test(False, is_valid("abbcegjk")) test(True, is_valid("abcdffaa")) test(True, is_valid("ghjaabcc")) test("abcdffaa", next(valid_passwords("abcdefgh"))) test("ghjaabcc", next(valid_passwords("ghijklmn"))) test("hepxxyzz", next(valid_passwords("hepxcrrq"))) test("heqaabcc", next(valid_passwords("hepxxyzz")))
def load_regex(filename, regex, script=__file__): return [ re.match(regex, line).groups() for line in load(filename, script=script) ] def load_happies(filename, script=__file__): happy_regex = r'(.*) would (.*) (.*) happiness units by sitting next to (.*).' return {(a, b): int(amount) * [-1, 1][act == 'gain'] for a, act, amount, b in load_regex( filename, regex=happy_regex, script=__file__)} def maximize_happiness(filename, add_yourself=False): happies = load_happies(filename) names = {a for a, _ in happies.keys()} if add_yourself: names.add(None) return max( sum( happies.get((a, b), 0) + happies.get((b, a), 0) for a, b in zip(p, chain(p[1:], [p[0]]))) for p in permutations(names)) if __name__ == "__main__": test(330, maximize_happiness('input-test-1.txt')) test(664, maximize_happiness('input.txt')) test(640, maximize_happiness('input.txt', add_yourself=True))
visited.add(value) def part2(filename, time): grids = {0: load_grid(filename, script=__file__)} blank_grid = {(x, y): '.' for y in range(h) for x in range(w)} grids[0][mid_x, mid_y] = blank_grid[mid_x, mid_y] = '?' lowest, highest = 0, 0 for _ in range(1, time+1): if not is_blank_grid(grids[lowest]): lowest -= 1 grids[lowest] = copy(blank_grid) if not is_blank_grid(grids[highest]): highest += 1 grids[highest] = copy(blank_grid) grids = {i: next_grid_recursive(grids, i) for i, grid in grids.items()} for i, grid in sorted(grids.items()): print('Depth {}:'.format(i)) draw_bugs(grid) return sum(grid[x, y] == '#' for grid in grids.values() for y in range(h) for x in range(w)) if __name__== "__main__": test(2129920, part1('input-test-1.txt')) test(32506911, part1('input.txt')) test(99, part2('input-test-1.txt', 10)) test(2025, part2('input.txt', 200))
(x+1, y)) == grid.get((x-1, y)) == grid.get((x, y+1)) == grid.get((x, y-1)) == '#'] return sum(x*y for x, y in intersections) def parse_input(lines): return map(ord, ('{}\n' * len(lines)).format(*lines)) def parse_vararg_input(**args): return parse_input(args.values()) def part2(filename): memory = load_memory(filename, script=__file__) memory[0] = 2 input = parse_vararg_input( main='A,A,B,C,B,C,B,C,C,A', A='L,10,R,8,R,8', B='L,10,L,12,R,8,R,10', C='R,10,L,12,R,10', video='n' ) prog = Program(memory, input) run = prog.run_computer() return list(run)[-1] if __name__ == "__main__": test(6212, part1('input.txt')) test(1016741, part2('input.txt'))
def emulate(ops): g = nx.DiGraph() for target, (_, vars) in ops.items(): for var in vars: g.add_edge(var, target) wires = {} for target in nx.topological_sort(g): wires[target] = ops[target][0](wires) return wires def solve(filename, letter, override_letter=None): ops = load_instructions(filename) if override_letter: value = solve(filename, letter) ops[override_letter] = lambda w: value, [] return emulate(ops)[letter] if __name__== "__main__": test(72, solve('input-test-1.txt', 'd')) test(507, solve('input-test-1.txt', 'e')) test(492, solve('input-test-1.txt', 'f')) test(114, solve('input-test-1.txt', 'g')) test(65412, solve('input-test-1.txt', 'h')) test(65079, solve('input-test-1.txt', 'i')) test(123, solve('input-test-1.txt', 'x')) test(456, solve('input-test-1.txt', 'y')) test(16076, solve('input.txt', 'a')) test(2797, solve('input.txt', 'a', override_letter='b'))
return zip_longest(fillvalue=fillvalue, *args) def paint(prog, initial_color): dx, dy = DIRS[0] x, y = 0, 0 grid = {(x, y): initial_color} for color, right in grouper(prog.run_computer(), 2): grid[x, y] = color dx, dy = next_dir(dx, dy, 1 if right else -1) x, y = x+dx, y+dy prog.input.append(grid.get((x, y), 0)) return grid def draw(grid, out=' *'): min_x = min(x for x, y in grid) max_x = max(x for x, y in grid) min_y = min(y for x, y in grid) max_y = max(y for x, y in grid) for y in range(min_y, max_y + 1): print(''.join(out[grid.get((x, y), 0)] for x in range(min_x, max_x + 1))) def solve(filename, initial_color): memory = load_memory(filename, script=__file__) prog = Program(memory, [initial_color]) return paint(prog, initial_color) if __name__== "__main__": test(2088, len(solve('input.txt', 0))) test(249, len(solve('input.txt', 1))) draw(solve('input.txt', 1))
def part1(filename): scanner = Scanner(load_memory(filename, script=__file__)) return sum(scanner.scan(x, y) for y in range(50) for x in range(50)) def find_box(scanner, w, h): lx, y = next((x, y) for y in range(1, 10) for x in range(1, 10) if scanner.scan(x, y)) rx = next(x for x in range(9, 0, -1) if scanner.scan(x, y)) ranges = {} for y in count(y + 1): while not scanner.scan(lx, y): lx += 1 while scanner.scan(rx + 1, y): rx += 1 y0 = y - h + 1 if y0 in ranges and ranges[y0][0] <= lx + w - 1 <= ranges[y0][1]: return lx, y0 ranges[y] = (lx, rx) def part2(filename): scanner = Scanner(load_memory(filename, script=__file__)) return find_box(scanner, 100, 100) if __name__ == "__main__": test(213, part1('input.txt')) test((783, 987), part2('input.txt'))
def part2(filename): memory = load_memory(filename, script=__file__) memory[0] = 2 prog = Program(memory) grid = {} ball_x = paddle_x = score = None block_count = 0 class PaddleInput: popleft = lambda self: sign(ball_x - paddle_x) prog.input = PaddleInput() for x, y, id in grouper(prog.run_computer(), 3): if (x, y) == (-1, 0): score = id if block_count == 0: return score else: if id == 2: block_count += 1 elif id == 3: paddle_x = x elif id == 4: ball_x = x elif id == 0 and grid.get((x, y)) == 2: block_count -= 1 grid[x, y] = id draw(grid, out=' |#-o') if __name__ == "__main__": test(398, part1('input.txt')) test(19447, part2('input.txt'))
#!/usr/bin/env python3 from day01.main import load, test def load_dimensions(filename, script=__file__): return [map(int, line.split('x')) for line in load(filename, script=script)] def wrapping_paper(w, l, h): return 2*l*w + 2*w*h + 2*h*l + w*l*h//max(w,l,h) def ribbon(w, l, h): return 2*(w + l + h - max(w,l,h)) + w*l*h def part1(filename): dimensions = load_dimensions(filename) return sum(wrapping_paper(w, l, h) for w, l, h in dimensions) def part2(filename): dimensions = load_dimensions(filename) return sum(ribbon(w, l, h) for w, l, h in dimensions) if __name__== "__main__": test(58, part1('input-test-1.txt')) test(43, part1('input-test-2.txt')) test(1586300, part1('input.txt')) test(34, part2('input-test-1.txt')) test(14, part2('input-test-2.txt')) test(3737498, part2('input.txt'))
elif op == 'jmp': idx += amt - 1 idx += 1 return idx, acc def part1(filename): prog = list(load_instructions(filename)) return run_prog(prog)[1] def part2(filename): prog = list(load_instructions(filename)) n = len(prog) for i in range(n): if prog[i][0] != 'acc': prog[i][0], temp = 'op' if prog[i][0] == 'jmp' else 'op', prog[i][ 0] idx, acc = run_prog(prog) if idx == n: return acc prog[i][0] = temp if __name__ == "__main__": test(5, part1('input-test-1.txt')) test(1939, part1('input.txt')) test(8, part2('input-test-1.txt')) test(2212, part2('input.txt'))
def load_grid(filename, script=__file__): rows = [line for line in load(filename, script=script)] return {(x, y): cell for y, row in enumerate(rows) for x, cell in enumerate(row)} def count_trees_on_slope(grid, right, down): width, height = size(grid) trees = x = 0 for y in range(down, height, down): x = (x + right) % width trees += grid[x, y] == '#' return trees def part1(filename, right, down): grid = load_grid(filename) return count_trees_on_slope(grid, right, down) def part2(filename): grid = load_grid(filename) return prod(count_trees_on_slope(grid, right, down) for right, down in [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]) if __name__ == "__main__": test(7, part1('input-test-1.txt', 3, 1)) test(254, part1('input.txt', 3, 1)) test(336, part2('input-test-1.txt')) test(1666768320, part2('input.txt'))
window.popleft() window.append(num) def part1(filename, size): nums = load_ints(filename, script=__file__) return find_key(nums, size) def part2(filename, size): nums = list(load_ints(filename, script=__file__)) key = find_key(nums, size) window = deque() window_sum = 0 for num in nums: if window_sum < key: window.append(num) window_sum += num while window_sum > key: window_sum -= window.popleft() if window_sum == key: return max(window) + min(window) if __name__ == "__main__": test(127, part1('input-test-1.txt', 5)) test(14144619, part1('input.txt', 25)) test(62, part2('input-test-1.txt', 5)) test(1766397, part2('input.txt', 25))
#!/usr/bin/env python3 import re from day01.main import load, test def looksee(digits): return ''.join(str(len(a)) + b for a, b in re.findall(r'((.)\2*)', digits)) def looksee_loop(digits, n): for _ in range(n): digits = looksee(digits) return digits if __name__== "__main__": test("11", looksee("1")) test("21", looksee("11")) test("1211", looksee("21")) test("111221", looksee("1211")) test("312211", looksee("111221")) test("312211", looksee_loop("1", n=5)) test(360154, len(looksee_loop("1113122113", n=40))) test(5103798, len(looksee_loop("1113122113", n=50)))