def puzzle_2(test_input=None): def compute_subtree_weights(node): node['subtree_weight'] = node['weight'] for callee in node['callees']: node['subtree_weight'] += compute_subtree_weights(stacks[callee]) return node['subtree_weight'] def balance_subtree(node, parent_weight=None): subtree = node target_weight = 0 weights = [ stacks[callee]['subtree_weight'] for callee in node['callees'] ] if len(weights) > 1: target_weight = weights[0 if weights.count(weights[0]) > 1 else 1] for callee in node['callees']: if stacks[callee]['subtree_weight'] != target_weight: subtree = stacks[callee] if subtree != node: return balance_subtree(subtree, target_weight) else: return parent_weight - len(node['callees']) * target_weight stacks = test_input if test_input else aocinput.input_for_day(7) root_node = stacks[puzzle_1()] compute_subtree_weights(root_node) return balance_subtree(root_node)
def puzzle_2(test_input=None): memory_map = test_input if test_input else aocinput.input_for_day(22) (y, x) = (0, 0) direction = 0 infection_count = 0 for _ in range(10000000): if y not in memory_map: memory_map[y] = {} if x not in memory_map[y]: memory_map[y][x] = '.' if memory_map[y][x] == '.': direction = (direction + 3) % 4 memory_map[y][x] = 'W' elif memory_map[y][x] == 'W': memory_map[y][x] = '#' infection_count += 1 elif memory_map[y][x] == '#': direction = (direction + 1) % 4 memory_map[y][x] = 'F' elif memory_map[y][x] == 'F': direction = (direction + 2) % 4 memory_map[y][x] = '.' if direction in [0, 2]: y += 1 if direction == 0 else -1 else: x += 1 if direction == 1 else -1 return infection_count
def puzzle_1(test_input=None): digits = test_input if test_input else aocinput.input_for_day(1) solution = int(digits[0]) if digits[0] == digits[len(digits) - 1] else 0 for i in range(0, len(digits) - 1): if digits[i] == digits[i + 1]: solution += int(digits[i]) return solution
def puzzle_2(test_input=None): input = test_input if test_input else aocinput.input_for_day(3) mem = {(0, 0): 1} position = (0, 0) directions = [(1, 0), (0, 1), (-1, 0), (0, -1)] direction = directions[0] direction_steps_max = 1 direction_steps = 0 pivots = 0 value = 0 while value < input: position = (position[0] + direction[0], position[1] + direction[1]) direction_steps += 1 for x in range(position[0] - 1, position[0] + 2): for y in range(position[1] - 1, position[1] + 2): if (x, y) in mem: value += mem[(x, y)] if value < input: mem[position] = value value = 0 if direction_steps == direction_steps_max: direction = directions[(directions.index(direction) + 1) % 4] direction_steps = 0 pivots += 1 if pivots % 2 == 0: direction_steps_max += 1 return value
def puzzle_2(test_input=None): states = test_input if test_input else aocinput.input_for_day(20) annihilated_particles = [] remaining_count = 0 flatline_count = 0 while True: occupied_positions = {} for p in range(len(states)): if p not in annihilated_particles: pos = states[p][0] v = states[p][1] a = states[p][2] v = (v[0] + a[0], v[1] + a[1], v[2] + a[2]) pos = (pos[0] + v[0], pos[1] + v[1], pos[2] + v[2]) if pos in occupied_positions: occupied_positions[pos].append(p) else: occupied_positions[pos] = [p] states[p][0] = pos states[p][1] = v for position in occupied_positions: if len(occupied_positions[position]) > 1: for p in occupied_positions[position]: annihilated_particles.append(p) if len(states) - len(annihilated_particles) == remaining_count: flatline_count += 1 if flatline_count > 100: break else: remaining_count = len(states) - len(annihilated_particles) return remaining_count
def puzzle_1(test_input=None): def bridge_strength(bridge): strength = 0 for component in bridge: strength += component[0] + component[1] return strength def continue_bridge(bridge, required_pin): sub_bridges = [] for component in components: if component not in bridge and required_pin in component: next_pin = component[1 if component[0] == required_pin else 0] sub_bridges.append(continue_bridge(bridge + [component], next_pin)) if len(sub_bridges) == 0: return bridge max_strength = 0 strongest_bridge = [] for sub_bridge in sub_bridges: strength = bridge_strength(sub_bridge) if strength > max_strength: max_strength = strength strongest_bridge = sub_bridge return strongest_bridge components = test_input if test_input else aocinput.input_for_day(24) return bridge_strength(continue_bridge([], 0))
def puzzle_2(test_input=None): links = test_input if test_input else aocinput.input_for_day(12) grouped_programs = [] key_programs = [] num_groups = -1 group_size = -1 group = set([]) while len(key_programs) > num_groups: num_groups = len(key_programs) for program in links.keys(): if len(group) == 0 and program not in grouped_programs: group.add(program) grouped_programs.append(program) key_programs.append(program) while len(group) > group_size: group_size = len(group) for program in links.keys(): if program not in group: for linked_program in links[program]: if linked_program in group: group.add(program) grouped_programs.append(program) group_size = -1 group = set([]) return len(key_programs)
def puzzle_1(test_input=None): steps = test_input if test_input else aocinput.input_for_day(11) position = (0.0, 0.0) deltas = hexagonal_deltas() for step in steps: position = (position[0] + deltas[step][0], position[1] + deltas[step][1]) return compute_distance(position)
def puzzle_1(test_input=None): key = test_input if test_input else aocinput.input_for_day(14) used_blocks = 0 for i in range(0, 128): row = day10.puzzle_2("%s-%d" % (key, i)) used_blocks += bin(int(row, 16))[2:].count('1') return used_blocks
def puzzle_2(test_input=None): def int_or_register(value): try: return int(value) except ValueError: return registers[program][value] instructions = test_input if test_input else aocinput.input_for_day(18) registers = {0: {'p': 0}, 1: {'p': 1}} queue = [[], []] state = [1, 1] # 1: running; 0: waiting; -1: terminated step = [0, 0] program = 0 snd_count = [0, 0] while True: instruction = instructions[step[program]] elements = instruction.split(' ') operator = elements[0] register = elements[1] if register not in registers[program]: registers[program][register] = 0 value = int_or_register(elements[2]) if len(elements) > 2 else None did_jump = False did_swap = False if operator == 'snd': queue[1 - program].append(registers[program][register]) snd_count[program] += 1 elif operator == 'set': registers[program][register] = value elif operator == 'add': registers[program][register] += value elif operator == 'mul': registers[program][register] *= value elif operator == 'mod': registers[program][register] %= value elif operator == 'rcv': if len(queue[program]) > 0: registers[program][register] = queue[program].pop(0) state[program] = 1 else: if state[1 - program] == -1: break if state[1 - program] == 0 and len(queue[1 - program]) == 0: break state[program] = 0 program = 1 - program did_swap = True elif operator == 'jgz': if int_or_register(register) > 0: step[program] += value did_jump = True if not did_jump and not did_swap: step[program] += 1 if step[program] not in range(0, len(instructions)): if state[1 - program] == -1: break state[program] = -1 program = 1 - program return snd_count[1]
def puzzle_2(test_input=None): digits = test_input if test_input else aocinput.input_for_day(1) count = len(digits) solution = 0 for i in range(0, len(digits)): if digits[i] == digits[(i + count / 2) % count]: solution += int(digits[i]) return solution
def puzzle_1(test_input=None): stacks = test_input if test_input else aocinput.input_for_day(7) callees = set() for program in stacks: stack = stacks[program] for callee in stack['callees']: if callee in stacks: callees.add(callee) return list(set(stacks.keys()).difference(callees))[0]
def puzzle_2(): rows = aocinput.input_for_day(2) even_division_sum = 0 for row in rows: for dividend in row: for divisor in row: if dividend != divisor and dividend % divisor == 0: even_division_sum += dividend / divisor return even_division_sum
def puzzle_1(test_input=None): scan_ranges = test_input if test_input else aocinput.input_for_day(13) penalty = 0 for depth in scan_ranges.keys(): scan_range = scan_ranges[depth] if depth % (scan_range - 1) == 0 and (depth / (scan_range - 1)) % 2 == 0: penalty += depth * scan_range return penalty
def puzzle_1(test_input=None): states = test_input if test_input else aocinput.input_for_day(20) min_a = 100000000 min_p = 0 for p in range(len(states)): a = abs(states[p][2][0]) + abs(states[p][2][1]) + abs(states[p][2][2]) if a < min_a: min_a = a min_p = p return min_p
def puzzle_1(test_input=None, iterations=40000000): generator_inputs = test_input if test_input else aocinput.input_for_day(15) result_1 = generator_inputs[0] result_2 = generator_inputs[1] match_count = 0 for _ in xrange(0, iterations): result_1 = (result_1 * 16807) % 2147483647 result_2 = (result_2 * 48271) % 2147483647 if result_1 & 65535 == result_2 & 65535: match_count += 1 return match_count
def puzzle_1(test_input=None): steps = test_input if test_input else aocinput.input_for_day(17) position = 0 spinlock = [position] value = 1 while value < 2018: position = (position + (steps % value)) % value spinlock.insert(position + 1, value) position += 1 value += 1 return spinlock[position + 1]
def puzzle_2(test_input=None): steps = test_input if test_input else aocinput.input_for_day(17) position = 0 value = 1 value_at_1 = 0 while value < 50000000: position = (position + steps) % value if position == 0: value_at_1 = value position += 1 value += 1 return value_at_1
def puzzle_1(test_input=None): links = test_input if test_input else aocinput.input_for_day(12) group_with_0 = set('0') group_size = 0 iterations = 0 while len(group_with_0) > group_size: group_size = len(group_with_0) for program in links.keys(): if program not in group_with_0: for linked_program in links[program]: iterations += 1 if linked_program in group_with_0: group_with_0.add(program) return len(group_with_0)
def puzzle_2(test_input=None): scan_ranges = test_input if test_input else aocinput.input_for_day(13) delay = 0 collisions = 1 while collisions > 0: collisions = 0 delay += 1 for depth in scan_ranges.keys(): scan_range = scan_ranges[depth] if (depth + delay) % (scan_range - 1) == 0 and ( (depth + delay) / (scan_range - 1)) % 2 == 0: collisions += 1 break return delay
def puzzle_1(test_input=None): input = test_input if test_input else aocinput.input_for_day(3) quadrant_value = 3 quadrant_size = 2 pivots = 0 while quadrant_value < input: quadrant_value += quadrant_size pivots += 1 if quadrant_value < input and pivots % 2 == 0: quadrant_size += 1 manhattan_distance = 2 * (pivots / 4 + 1) - (quadrant_value - input) if pivots % 4 == 3: manhattan_distance += 1 return manhattan_distance
def puzzle_2(test_input=None): input = test_input if test_input else aocinput.input_for_day(10, 2) lengths = map(lambda character: ord(character), input) lengths += [17, 31, 73, 47, 23] sparse_hash = compute_sparse_hash(lengths, 64) dense_hash = [] xor_result = 0 for i in range(256): if i > 0 and i % 16 == 0: dense_hash.append(xor_result) xor_result = 0 xor_result ^= sparse_hash[i] dense_hash.append(xor_result) knot_hash = '' for hash_element in dense_hash: knot_hash += format(hash_element, '02x') return knot_hash
def puzzle_1(test_input=None): def int_or_register(value): try: return int(value) except ValueError: return registers[value] instructions = test_input if test_input else aocinput.input_for_day(18) registers = {} last_sound_played = None step = 0 while step in range(0, len(instructions)): instruction = instructions[step] elements = instruction.split(' ') operator = elements[0] register = elements[1] if register not in registers: registers[register] = 0 value = int_or_register(elements[2]) if len(elements) > 2 else None did_jump = False if operator == 'snd': last_sound_played = registers[register] elif operator == 'set': registers[register] = value elif operator == 'add': registers[register] += value elif operator == 'mul': registers[register] *= value elif operator == 'mod': registers[register] %= value elif operator == 'rcv': if registers[register] > 0: return last_sound_played elif operator == 'jgz': if registers[register] > 0: step += value did_jump = True if not did_jump: step += 1
def puzzle_2(test_input=None, max_comparisons=5000000): generator_inputs = test_input if test_input else aocinput.input_for_day(15) result_1 = generator_inputs[0] result_2 = generator_inputs[1] offset_1 = 0 offset_2 = 0 comparisons = 0 match_count = 0 while comparisons < max_comparisons: if offset_1 <= comparisons: result_1 = (result_1 * 16807) % 2147483647 if result_1 % 4 == 0: offset_1 += 1 if offset_2 <= comparisons: result_2 = (result_2 * 48271) % 2147483647 if result_2 % 8 == 0: offset_2 += 1 if offset_1 > comparisons and offset_2 > comparisons: if result_1 & 65535 == result_2 & 65535: match_count += 1 comparisons += 1 return match_count
def puzzle_2(test_input=None): def merge_regions(result_region, redundant_region): for (row, column) in regions[redundant_region]: regions[result_region].append((row, column)) region_map[(row, column)] = result_region regions.pop(redundant_region) return result_region key = test_input if test_input else aocinput.input_for_day(14) rows = [] region_map = {} current_region = None encountered_regions = 0 regions = {} for i in range(0, 128): row = bin(int(day10.puzzle_2("%s-%d" % (key, i)), 16))[2:] rows.append(("%128s" % row).replace(' ', '0')) for i in range(0, 128): for j in range(0, 128): if rows[i][j] == '0': region_map[(i, j)] = 0 current_region = None else: region_above = region_map[(i - 1, j)] if i > 0 else None if not current_region and rows[i][j] == '1': if region_above: current_region = region_above else: encountered_regions += 1 current_region = encountered_regions regions[current_region] = [] else: if region_above and region_above != current_region: current_region = merge_regions(region_above, current_region) region_map[(i, j)] = current_region regions[current_region].append((i, j)) current_region = None return len(regions)
def puzzle_1(test_input=None): def int_or_register(value): try: return int(value) except ValueError: return registers[value] instructions = test_input if test_input else aocinput.input_for_day(23) registers = {} step = 0 mul_count = 0 while True: instruction = instructions[step] elements = instruction.split(' ') operator = elements[0] register = elements[1] if register not in registers: registers[register] = 0 value = int_or_register(elements[2]) if len(elements) > 2 else None did_jump = False if operator == 'set': registers[register] = value elif operator == 'sub': registers[register] -= value elif operator == 'mul': registers[register] *= value mul_count += 1 elif operator == 'mod': registers[register] %= value elif operator == 'jnz': if int_or_register(register) != 0: step += value did_jump = True if not did_jump: step += 1 if step not in range(0, len(instructions)): break return mul_count
def puzzle_1(test_input=None, start_state=None): moves = test_input if test_input else aocinput.input_for_day(16) programs = list(start_state) if start_state else list('abcdefghijklmnop') for move in moves: move_type = move[0] instruction = move[1:] if move_type == 's': tail = programs[-int(instruction):] head = programs[:16 - int(instruction)] programs = tail + head elif move_type == 'x': (a, b) = instruction.split('/') program_a = programs[int(a)] program_b = programs[int(b)] programs[int(a)] = program_b programs[int(b)] = program_a else: (program_a, program_b) = instruction.split('/') index_a = programs.index(program_a) index_b = programs.index(program_b) programs[index_a] = program_b programs[index_b] = program_a return ''.join(programs)
def puzzle_1_recursive(test_input=None): def linked_to_0(program): if program in group_0: return True else: linked = False for linked_program in links[program]: puzzle_1_recursive.iterations += 1 if linked_program not in visiting: visiting.add(linked_program) linked = linked or linked_to_0(linked_program) visiting.remove(linked_program) if linked: group_0.add(program) return linked links = test_input if test_input else aocinput.input_for_day(12) group_0 = set('0') visiting = set() puzzle_1_recursive.iterations = 0 for program in links.keys(): linked_to_0(program) print("Iterations: %d" % puzzle_1_recursive.iterations) return len(group_0)
def puzzle_2(test_input=None): rules = test_input if test_input else aocinput.input_for_day(21) return day21_shared(rules, 2)
def puzzle_2(test_input=None): passphrases = test_input if test_input else aocinput.input_for_day(4) return day04_shared(passphrases, 2)