def part2(seed=puzzle_input(22), bursts=10000000): INFECT_COUNT = 0 grid = {(y, x): 'C' if cell_status == '.' else 'I' for y, row in enumerate(seed) for x, cell_status in enumerate(row)} map_height = max(k[0] for k in grid) + 1 map_width = max(k[1] for k in grid) + 1 position = (map_height // 2, map_width // 2) # row, Col current_direction = 1 # UP def current_node(): return grid.setdefault(position, 'C') for _ in range(bursts): if current_node() == 'C': grid[position] = 'W' current_direction = (current_direction - 1) % 4 elif current_node() == 'W': grid[position] = 'I' INFECT_COUNT += 1 elif current_node() == 'I': grid[position] = 'F' current_direction = (current_direction + 1) % 4 elif current_node() == 'F': grid[position] = 'C' current_direction = (current_direction + 2) % 4 position = DIRECTIONS[current_direction](*position) return INFECT_COUNT
def parse_input(): translations = {} for line in puzzle_input(21): before, after = line.split(" => ") translations[before] = Grid(after) return translations
def part1(seed=puzzle_input(22), bursts=10000): # count the number of times we turn a node from CLEAN to INFECTED INFECT_COUNT = 0 # we use a dict to avoid extending our grid when position goes out of bounds grid = {(y, x): cell_status for y, row in enumerate(seed) for x, cell_status in enumerate(row)} map_height = max(k[0] for k in grid) + 1 map_width = max(k[1] for k in grid) + 1 position = (map_height // 2, map_width // 2) # row, Col # use for turning left/right from our direction current_direction = 1 # UP def current_node(): return grid.setdefault(position, CLEAN) for _ in range(bursts): if current_node() == INFECTED: current_direction = (current_direction + 1) % 4 grid[position] = CLEAN else: current_direction = (current_direction - 1) % 4 grid[position] = INFECTED INFECT_COUNT += 1 position = DIRECTIONS[current_direction](*position) return INFECT_COUNT
from common import puzzle_input, parse_int from collections import defaultdict PUZZLE_INPUT = puzzle_input(20) def add(xs, ys): return tuple(x + y for x, y in zip(xs, ys)) class Particle: next_id = 0 def __init__(self, position, velocity, acceleration): self.id = self.next_id Particle.next_id += 1 assert len(position) == 3 self.position = position assert len(velocity) == 3 self.velocity = velocity assert len(acceleration) == 3 self.acceleration = acceleration def __repr__(self): return f"Particle({self.position}, {self.velocity}, {self.acceleration})" @classmethod def from_input(cls, line): """Create new Particle object from puzzle input""" *data, _trash = line.split('>') data = [parse_int(triplet) for triplet in data] return cls(*data)
def part2(data=puzzle_input(4)): def valid(wordlist): wordlist = [cat(sorted(word)) for word in wordlist] return len(wordlist) == len(set(wordlist)) return sum(map(valid, [line.split() for line in data]))
def part1(data=puzzle_input(4)): def valid(wordlist): return len(wordlist) == len(set(wordlist)) return sum(map(valid, [line.split() for line in data]))
from itertools import tee from common import puzzle_input PUZZLE_INPUT = puzzle_input(1)[0] def circular_chunk(it: str): """ yields it[0], it[1]: it[1], it[2]:, it[2], it[3]... it[n-2], it[n-1] as well as it[n-1], it[0] """ a, b = tee(it) next(b) yield from zip(a, b) yield it[-1], it[0] def halfway_chunk(it: str): """ yields pairs of elements opposite from eachother """ n = len(it) distance = n // 2 for i in range(n): j = (i + distance) % n yield it[i], it[j] def part1(data): chunks = circular_chunk(data) only_same = (int(a) for a, b in chunks if a == b)
def parse_line(line): if '->' in line: first, second = line.split('->') second = second.strip().split(', ') else: first = line second = [] name, weight = first.strip().split() weight = int(weight.strip('()')) return Node(name, weight), second PUZZLE_INPUT = [parse_line(line) for line in puzzle_input(7)] def part1(data=PUZZLE_INPUT): has_children = set() is_child = set() for prog, children in data: if children: is_child = is_child.union(set(children)) has_children.add(prog) for prog, _ in data: if (prog in has_children) and (prog.name not in is_child): return prog
def parse_input(data=puzzle_input(12)): for line in data: left, right = line.split(' <-> ') right = set(map(int, right.split(','))) yield int(left), right
from common import puzzle_input, parse_int PUZZLE_INPUT = dict(map(parse_int, puzzle_input(13))) def scanner_on_top(rnge, turn=0): if rnge == 0: return False trip_time = (rnge - 1) * 2 return turn % trip_time == 0 def part1(data=PUZZLE_INPUT): return sum(depth * range for depth, range in data.items() if scanner_on_top(range, depth)) def part2(data=PUZZLE_INPUT): delay = 1 while True: if not any( scanner_on_top(rnge, depth + delay) for depth, rnge in data.items()): return delay else: delay += 1 if __name__ == '__main__': example = {0: 3, 1: 2, 4: 4, 6: 4} assert part1(example) == 24
from common import puzzle_input, parse_int PUZZLE_INPUT = puzzle_input(16)[0].split(',') def cat(args): return ''.join(args) def part1(instructions=PUZZLE_INPUT, progs=None): if progs is None: progs = list('abcdefghijklmnop') for line in instructions: cmd = line.startswith if cmd('x'): a, b = parse_int(line) progs[b], progs[a] = progs[a], progs[b] elif cmd('p'): a, b = line[1], line[3] ai, bi = progs.index(a), progs.index(b) progs[ai], progs[bi] = progs[bi], progs[ai] elif cmd('s'): n = int(line[1:]) progs = progs[-n:] + progs[:-n] return ''.join(progs) def part2(instructions=PUZZLE_INPUT): count = 0
# https://adventofcode.com/2018/day/1 from itertools import accumulate, cycle from common import puzzle_input PUZZLE_INPUT = [int(i) for i in puzzle_input(1)] def seen_twice(iterable): seen = set() for element in iterable: if element in seen: yield element seen.add(element) def part1(data=PUZZLE_INPUT): return sum(data) def part2(data=PUZZLE_INPUT): return next(seen_twice(accumulate(cycle(data)))) if __name__ == "__main__": print("Part 1 result:", part1()) print("Part 2 result:", part2())
from common import puzzle_input PUZZLE_INPUT = list(puzzle_input(5)[0]) def part1(data=PUZZLE_INPUT[:]): while True: for i, char in enumerate(data[:-1]): if char.swapcase() == data[i + 1]: # we have a pair data.pop(i + 1) data.pop(i) break # restart for loop else: return len(data) def part2(data=PUZZLE_INPUT): """Like part1, but 26 times""" from string import ascii_lowercase results = [] for letter in ascii_lowercase: print('calculating letter ', letter) letter_removed = [char for char in data if char.lower() != letter] results.append(part1(data=letter_removed)) return min(results) if __name__ == '__main__':
if parse_int(action): guard_id = parse_int(action)[0] elif action.endswith("falls asleep"): nap_start = timestamp elif action.endswith("wakes up"): duration = timestamp - nap_start # drop last one, which is when they wake up minutes = [ts.minute for ts in duration.range("minutes")][:-1] guard_log = guard_nap_minutes.setdefault(guard_id, []) guard_log.extend(minutes) return guard_nap_minutes PUZZLE_INPUT = prep_input(puzzle_input(4)) def part1(data=PUZZLE_INPUT): # find nappiest guard, guess which minute he is asleep guard, naps = max(data.items(), key=lambda tup: len(tup[1])) most_common_minute, count = Counter(naps).most_common(1)[0] return guard * most_common_minute # find most common minute asleep among that guards naps # multiple the minute and guard id together def part2(data=PUZZLE_INPUT): # find which guard naps most regularly
from itertools import combinations from common import puzzle_input PUZZLE_INPUT = [[int(num) for num in row.split()] for row in puzzle_input(2)] def find_quotient(nums: list): for pair in combinations(sorted(nums, reverse=True), 2): result, remainder = divmod(*pair) if remainder == 0: return result def part1(data=PUZZLE_INPUT): result = sum(max(row) - min(row) for row in data) return result def part2(data=PUZZLE_INPUT): result = sum(find_quotient(row) for row in data) return result if __name__ == '__main__': print('Part one result:', part1()) print('Part 2:', part2())
"https://adventofcode.com/2018/day/3" from common import puzzle_input, parse_int from collections import Counter PUZZLE_INPUT = [parse_int(line) for line in puzzle_input(3)] def square_inch_ids(x_offset, y_offset, width, height): """ generates a series representing the ids each square inch of fabric used for this claim """ start = y_offset * 1000 + x_offset for i in range(width): for j in range(height): yield start + i + (j * 1000) def part1(data=PUZZLE_INPUT): square_count = Counter() for _id, *square in PUZZLE_INPUT: square_count.update(square_inch_ids(*square)) return sum(count > 1 for count in square_count.values()) def part2(data=PUZZLE_INPUT): claim_ids = set()