for position, unit_type, unit in units: if (position, unit_type, unit) not in unit_positions: # Unit was already killed earlier in the round! continue enemies = [target for target in unit_positions.items() if target[0][1] != unit_type] if not enemies: # No enemies are left battle_in_progress = False hit_point_total = sum(unit_positions.values()) if attack_power['E'] == initial_attempt: aoc.print_solution(1, rounds * hit_point_total) elif (unit_type == 'E' and attack_power['E'] > initial_attempt): # Elves were successful aoc.print_solution(2, rounds * hit_point_total) elves_victorious = True break squares_in_range = [travel(position, direction) for direction in directions] if not any(enemy[0][0] in squares_in_range for enemy in enemies): # Move open_squares = set() for enemy in enemies:
puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.lines_to_list) cloth = {} claims = set() non_viable = set() oversubscription = 0 for claim in puzzle_input: parse = claim.split(' ') claim_number = int(parse[0][1:]) claims.add(claim_number) corner = [int(coord) for coord in parse[2][:-1].split(',')] size = [int(dimension) for dimension in parse[3].split('x')] for y in range(size[1]): for x in range(size[0]): inch = (corner[0] + x, corner[1] + y) claimed_inch = cloth.get(inch, None) if not claimed_inch: cloth[inch] = [claim_number] else: if len(claimed_inch) == 1: non_viable.add(claimed_inch[0]) oversubscription += 1 claimed_inch.append(claim_number) non_viable.add(claim_number) aoc.print_solution(1, oversubscription) aoc.print_solution(2, claims - non_viable)
from lib.aoclib import AOCLib from lib.pixelgrid import PixelGrid puzzle = (2017, 21) # Initialise the helper library aoc = AOCLib(puzzle[0]) # Get the puzzle input puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.lines_to_list) # print(puzzle_input) pixel_grid = PixelGrid(puzzle_input) # Puzzle solution parts 1 and 2 iterations = 0 while iterations < 18: pixel_grid.expand_grid() iterations += 1 if iterations == 5: aoc.print_solution(1, pixel_grid.count_pixels()) aoc.print_solution(2, pixel_grid.count_pixels())
# # Distance metric = (|x2-x1| + |y2-y1| + |z2-z1|) / 2 directions = { 'n': (0, 1, -1), 's': (0, -1, 1), 'ne': (1, 0, -1), 'nw': (-1, 1, 0), 'se': (1, -1, 0), 'sw': (-1, 0, 1) } #puzzle_input = ['ne','se','s'] position = (0, 0, 0) max_steps_from_origin = 0 for step in puzzle_input: position = (position[0] + directions[step][0], position[1] + directions[step][1], position[2] + directions[step][2]) steps_from_origin = hex_distance(position) if steps_from_origin > max_steps_from_origin: max_steps_from_origin = steps_from_origin aoc.print_solution(1, steps_from_origin) aoc.print_solution(2, max_steps_from_origin)
magic_2 = int(puzzle_input[12].split(' ')[2]) # I hated this. Really hated it. Not enjoyable in any way shape or form. part_1 = None part_2 = None history = set() r4 = 0 while part_2 is None: r5 = r4 | 0x10000 r4 = magic_1 while True: r4 = (((r4 + (r5 & 0xff)) & 0xFFFFFF) * magic_2) & 0xFFFFFF if r5 < 256: if part_1 is None: part_1 = r4 aoc.print_solution(1, part_1) else: if r4 not in history: history.add(r4) last_seen = r4 else: part_2 = last_seen break else: r5 //= 256 aoc.print_solution(1, part_2)
# print(puzzle_input) # Puzzle solution parts 1 and 2 program_length = len(puzzle_input) program = [instruction.split(' ') for instruction in puzzle_input] registers_0 = Registers({'p': 0}) registers_1 = Registers({'p': 1, 'part2': 0}) program_queues = [[], []] pc = [0, 0] while True: pc_inc_0 = process_instruction(0, program[pc[0]], registers_0, program_queues) pc_inc_1 = process_instruction(1, program[pc[1]], registers_1, program_queues) pc[0] += pc_inc_0 pc[1] += pc_inc_1 if (pc[0] < 0 or pc[0] >= program_length or pc[1] < 0 or pc[1] >= program_length or (pc_inc_0 == pc_inc_1 == 0)): break aoc.print_solution(1, registers_0['part1']) aoc.print_solution(2, registers_1['part2'])
infected = 0 while bursts: if grid.setdefault(position, '.') == '#': direction = (direction + 1) % 4 grid[position] = '.' else: direction = (direction - 1) % 4 grid[position] = '#' infected += 1 position = (position[0] + directions[direction][0], position[1] + directions[direction][1]) bursts -= 1 aoc.print_solution(1, infected) # Puzzle solution part 2 grid = start_grid.copy() position = (0, 0) direction = 0 bursts = 10000000 infected = 0 # . = clean, # = infected, F = flagged, W = weakened while bursts: node = grid.setdefault(position, '.')
while True: left, right = pots.get_extent() pots.start_generation() for pot_to_check in range(left - pattern_len // 2, right + pattern_len // 2 + 1): match = pots.get_pots(pot_to_check, pattern_len) if match in rules: pots.set_state(pot_to_check, rules[match]) else: pots.set_state(pot_to_check, False) pots.end_generation() potsum = pots.potsum() if generation == 20: aoc.print_solution(1, potsum) plants = pots.get_pattern() if plants in generations: repeat_generation = generations.index(plants) cycle = generation - repeat_generation potsum_difference = potsum - potsums[repeat_generation] if repeat_generation and generation >= 20: break generations.append(plants) potsums.append(potsum) generation += 1 big_number = 50000000000
while number < puzzle_input: d = (d + 1) % 4 number += steps x += steps * directions[d][0] y += steps * directions[d][1] increment = not increment if increment: steps += 1 # Backtrack if the target number is not on a corner if number > puzzle_input: x -= (number-puzzle_input) * directions[d][0] y -= (number-puzzle_input) * directions[d][1] aoc.print_solution('1#1', abs(x) + abs(y)) # Puzzle solution part 1 - no loops required! # Diagonal right & down are perfect squares # Find odd perfect square >= puzzle_input and count backwards # Use symmetry to our advantage! square_size = 2*(math.ceil(math.sqrt(puzzle_input))//2) + 1 top_left = (square_size - 2)*square_size + 2 difference = square_size*square_size - max(puzzle_input, 2*top_left - puzzle_input) x_diff = min(square_size - 1, difference) y_diff = max(0, difference - square_size + 1) x = (square_size - 1)//2 - (x_diff if puzzle_input > top_left else y_diff) y = (1 - square_size)//2 + (y_diff if puzzle_input > top_left else x_diff)
for line in puzzle_input[1:]: decoded = line.split(' ') program.append((decoded[0], tuple(int(v) for v in decoded[1:]))) program_length = len(program) pc_reg = int(puzzle_input[0].split(' ')[1]) for reg_0_value in (0, 1): pc = 0 registers = [reg_0_value, 0, 0, 0, 0, 0] while 0 <= pc < program_length: if pc == 1: # Program is calculating the sum of the factors of N # where N = registers[4] when PC == 1 aoc.print_solution(1 + reg_0_value, sum(get_factors(registers[4]))) break op = program[pc][0] a, b, c = program[pc][1] registers[pc_reg] = pc if op[:3] == 'add': registers[c] = registers[a] + (b if op[3] == 'i' else registers[b]) elif op[:3] == 'mul': registers[c] = registers[a] * (b if op[3] == 'i' else registers[b]) elif op[:3] == 'ban': registers[c] = registers[a] & (b if op[3] == 'i' else registers[b]) elif op[:3] == 'bor': registers[c] = registers[a] | (b if op[3] == 'i' else registers[b]) elif op[:3] == 'set': registers[c] = a if op[3] == 'i' else registers[a] elif op[:2] == 'gt':
closest_to_origin = 0 for particle in range(num_particles): particle_v[particle][0] += particle_a[particle][0] particle_v[particle][1] += particle_a[particle][1] particle_v[particle][2] += particle_a[particle][2] particle_p[particle][0] += particle_v[particle][0] particle_p[particle][1] += particle_v[particle][1] particle_p[particle][2] += particle_v[particle][2] particle_d[particle] = sum( [abs(coord) for coord in particle_p[particle]]) if particle_d[particle] < particle_d[closest_to_origin]: closest_to_origin = particle for particle_1 in range(num_particles - 1): if not particle_c[particle_1]: if particle_p[particle_1] in particle_p[particle_1 + 1:]: collision = False for particle_2 in range(particle_1 + 1, num_particles): if (not particle_c[particle_2] and particle_p[particle_2] == particle_p[particle_1]): particle_c[particle_2] = True collision = True if collision: particle_c[particle_1] = True ticks -= 1 aoc.print_solution(1, closest_to_origin) aoc.print_solution(2, particle_c.count(False))
circle_size = len(circular_list) running_total = 0 for index in range(circle_size): index2 = (index + offset) % circle_size if circular_list[index] == circular_list[index2]: running_total += circular_list[index] return running_total puzzle = (2017, 1) # Initialise the helper library aoc = AOCLib(puzzle[0]) # Get the puzzle input as a list of integers puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.sequence_to_int) # print(puzzle_input) # Puzzle solution part 1: aoc.print_solution(1, solve_puzzle(puzzle_input, 1)) # Puzzle solution part 2 aoc.print_solution(2, solve_puzzle(puzzle_input, len(puzzle_input)//2))
elif c == '(': bracket_stack.append(current_position) else: new_position = (current_position[0] + directions[c][0], current_position[1] + directions[c][1]) if new_position not in maze: maze[new_position] = empty_room.copy() maze[new_position][backtrack[c]] = current_position maze[current_position][c] = new_position current_position = new_position index += 1 doors_passed_through = -1 next_rooms = [(0, 0)] visited = set() less_than_1000_doors = 0 while next_rooms: if doors_passed_through == 999: less_than_1000_doors = len(visited) doors_passed_through += 1 new_next_rooms = [] for next_room in next_rooms: new_next_rooms.extend([room for room in maze[next_room].values() if room and room not in visited]) visited.add(next_room) next_rooms = new_next_rooms aoc.print_solution(1, doors_passed_through) aoc.print_solution(1, len(visited) - less_than_1000_doors)
bridge = bridges.pop() valid_port = (bridge[-1][0] if bridge[-1][1] in bridge[-2] else bridge[-1][1]) valid_components = [component for component in components if valid_port in component and component not in bridge] if valid_components: for component in valid_components: new_bridge = bridge[:] new_bridge.append(component) bridges.append(new_bridge) else: bridge_strength = sum([sum([int(port) for port in component]) for component in bridge]) if bridge_strength > strongest_bridge: strongest_bridge = bridge_strength if len(bridge) > strongest_longest_bridge[0]: strongest_longest_bridge = (len(bridge), bridge_strength) elif len(bridge) == strongest_longest_bridge[0]: if bridge_strength > strongest_longest_bridge[1]: strongest_longest_bridge = (len(bridge), bridge_strength) aoc.print_solution(1, strongest_bridge) aoc.print_solution(2, strongest_longest_bridge[1])
# that it is supported by this X for program_name, program_data in program_table.items(): for supporting_program in program_data['supporting']: supporting_program_name = supporting_program['program_name'] program_table[supporting_program_name]['supported_by'] = program_name # The "root" programs are then the ones with empty "supported by" # lists (there should be only one according to the puzzle text) root_programs = [program_name for program_name, program_data in program_table.items() if program_data['supported_by'] is None] aoc.print_solution(1, ', '.join(root_programs)) # Puzzle solution part 2 # Traverse the tree we built previously from its root(s) and # bubble up the weights of each program to the supporting programs traverse_tree = root_programs[:] while traverse_tree: program_name = traverse_tree.pop() this_program = program_table[program_name] traverse_tree.extend(list(supporting['program_name'] for supporting
aoc = AOCLib(puzzle[0]) puzzle_input = aoc.get_puzzle_input(puzzle[1]).split(' ') number_of_players = int(puzzle_input[0]) last_marble = int(puzzle_input[6]) scores = [0] * number_of_players marble_to_play = 1 marbles = FunkyStructure(0) for puzzle_part in (1, 2): while marble_to_play <= last_marble: if marble_to_play % 23 == 0: marbles.rotate_by(7) removed_marble = marbles.pop_tail() scores[marble_to_play % number_of_players] += marble_to_play + removed_marble marbles.rotate_by(-1) else: marbles.rotate_by(-1) marbles.add(marble_to_play) marble_to_play += 1 aoc.print_solution(puzzle_part, max(scores)) last_marble *= 100
for layer in puzzle_input: layer_data = layer.split(': ') scanner_range[int(layer_data[0])] = int(layer_data[1]) * 2 - 2 number_of_layers = max(scanner_range.keys()) + 1 # Puzzle solution part 1 penalty = 0 for layer in scanner_range: if (layer % scanner_range[layer]) == 0: penalty += layer * ((scanner_range[layer] + 2) // 2) aoc.print_solution(1, penalty) # Puzzle solution part 2 # Condition for being caught at layer L with a delay D is # '(L + D) % R(L) == 0' # # Check each layer, aborting further checks for that delay if caught delay = 0 while True: for layer in scanner_range: if ((layer + delay) % scanner_range[layer]) == 0: delay += 1 break
from lib.aoclib import AOCLib from lib.knothash import KnotHash puzzle = (2017, 10) # Initialise the helper library aoc = AOCLib(puzzle[0]) # Get the puzzle input puzzle_input = aoc.get_puzzle_input(puzzle[1]) # print(puzzle_input) awful_hash_1 = KnotHash.get_hash(AOCLib.to_list_int(puzzle_input)) aoc.print_solution(1, awful_hash_1[0][0] * awful_hash_1[0][1]) puzzle_lengths = [ord(character) for character in puzzle_input] puzzle_lengths.extend([17, 31, 73, 47, 23]) awful_hash_2 = KnotHash.get_hash(puzzle_lengths, rounds=64) aoc.print_solution(2, awful_hash_2[1])
repeat_counts = {} for box_id in puzzle_input: letter_counts = {} for letter in box_id: letter_counts[letter] = letter_counts.get(letter, 0) + 1 box_letter_runs = {} for count in letter_counts.values(): box_letter_runs[count] = box_letter_runs.get(count, 0) + 1 for run_length, number in box_letter_runs.items(): repeat_counts[run_length] = repeat_counts.get(run_length, 0) + 1 aoc.print_solution(1, repeat_counts[2] * repeat_counts[3]) difference_pos = None correct_box_id = None for box_number, box_id_1 in enumerate(puzzle_input): for box_id_2 in puzzle_input[:box_number]: for index, (letter_1, letter_2) in enumerate(zip(box_id_1, box_id_2)): if letter_1 != letter_2: if difference_pos: difference_pos = None break else: difference_pos = index if difference_pos:
clean_stream = '' score = 0 for i, c in enumerate(puzzle_input): if skip_next: skip_next = False else: if c == '!': skip_next = True elif inside_garbage: if c == '>': inside_garbage = False else: garbage_count += 1 elif c == '<': inside_garbage = True else: if c == '{': unclosed_positions.append(i) elif c == '}': nesting_level = len(unclosed_positions) group_start = unclosed_positions.pop() group_positions.append((group_start, i, nesting_level)) score += nesting_level clean_stream += c aoc.print_solution(1, score) aoc.print_solution(2, garbage_count)
best_asteroid = None for asteroid in asteroids: rays = {} for other_asteroid in asteroids: if asteroid != other_asteroid: x, y = ((other_asteroid[0] - asteroid[0]), (other_asteroid[1] - asteroid[1])) direction = round(rounding_factor * atan2(x, y)) magnitude = sqrt(x * x + y * y) rays.setdefault(direction, []).append(magnitude) visible_asteroids = len(rays) if visible_asteroids > most_visible[0]: most_visible = (visible_asteroids, rays, asteroid) aoc.print_solution(1, most_visible[0]) visible_asteroids = most_visible[1] directions = sorted(visible_asteroids.keys()) asteroids_to_vaporise = 200 while True: for direction in directions: asteroids_in_direction = visible_asteroids[direction] if asteroids_in_direction: closest_asteroid_distance = min(asteroids_in_direction) asteroids_in_direction.remove(closest_asteroid_distance) asteroids_to_vaporise -= 1 if asteroids_to_vaporise == 0: break else:
# print(puzzle_input) begin_state = puzzle_input[0][-2] checksum_steps = int(puzzle_input[1].split()[-2]) state_machine = {} for state in range(3, len(puzzle_input), 10): next_state_0 = (int(puzzle_input[state + 2][-2]), 1 if puzzle_input[state + 3][-3] == 'h' else -1, puzzle_input[state + 4][-2]) next_state_1 = (int(puzzle_input[state + 6][-2]), 1 if puzzle_input[state + 7][-3] == 'h' else -1, puzzle_input[state + 8][-2]) state_machine[puzzle_input[state][-2]] = (next_state_0, next_state_1) # Puzzle solution cursor = 0 state = begin_state tape = {} while checksum_steps: current = tape.setdefault(cursor, 0) tape[cursor] = state_machine[state][current][0] cursor += state_machine[state][current][1] state = state_machine[state][current][2] checksum_steps -= 1 aoc.print_solution(1, sum(tape.values()))
aoc = AOCLib(puzzle[0]) # Get the puzzle input puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.to_list) # print(puzzle_input) # Puzzle solution part 1 num_programs = 16 start_programs = [chr(97 + c) for c in range(num_programs)] programs = dance(start_programs, puzzle_input) aoc.print_solution(1, ''.join(programs)) # Puzzle solution part 2 dances = 1000000000 # Find a cycle in the output. cycle_length = 1 while programs != start_programs: programs = dance(programs, puzzle_input) cycle_length += 1 additional_dances = dances % cycle_length
cond_num_val = int(parsed_instruction[6]) cond_oper = parsed_instruction[5] if cond_oper == '<': cond_matched = (cond_reg_val < cond_num_val) elif cond_oper == '>': cond_matched = (cond_reg_val > cond_num_val) elif cond_oper == '<=': cond_matched = (cond_reg_val <= cond_num_val) elif cond_oper == '>=': cond_matched = (cond_reg_val >= cond_num_val) elif cond_oper == '==': cond_matched = (cond_reg_val == cond_num_val) else: cond_matched = (cond_reg_val != cond_num_val) if cond_matched: increment = int(parsed_instruction[2]) if parsed_instruction[1] == 'dec': increment = -increment registers[parsed_instruction[0]] += increment if registers[parsed_instruction[0]] > max_value: max_value = registers[parsed_instruction[0]] aoc.print_solution( 1, max([register_value for register_value in registers.values()])) aoc.print_solution(2, max_value)
# Use a cache of part 1's answer as it takes a moderately # long time to calculate. hash_outputs = aoc.retrieve_some_data(puzzle[1], 'part1') if hash_outputs is None: hash_outputs = [ int(KnotHash.get_hash(hash_input, rounds=64)[1], 16) for hash_input in hash_inputs ] aoc.cache_some_data(puzzle[1], 'part1', hash_outputs) used_block_count = sum([count_bits(row_hash) for row_hash in hash_outputs]) aoc.print_solution(1, used_block_count) # Puzzle solution part 2 grid = {} for y in range(num_rows): for x in range(num_cols): grid[(x, y)] = -1 if (hash_outputs[y] & (1 << x)) else 0 neighbour_offsets = ((1, 0), (0, 1), (-1, 0), (0, -1)) contiguous_area = 0 for start_position in range(num_rows * num_cols): x = start_position % num_cols y = start_position // num_cols
puzzle = (2019, 2) # Initialise the helper library aoc = AOCLib(puzzle[0]) puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.to_list_int) magic_number = 19690720 part_one = puzzle_input[:] part_one[1:3] = [12, 2] part_one_solution = run_program(part_one) aoc.print_solution(1, part_one_solution) for noun in range(100): for verb in range(100): part_two = puzzle_input[:] part_two[1:3] = [noun, verb] part_two_solution = run_program(part_two) if part_two_solution == magic_number: break else: continue break aoc.print_solution(2, 100 * noun + verb)
from lib.aoclib import AOCLib from intcode_computer import IntcodeComputer puzzle = (2019, 9) # Initialise the helper library aoc = AOCLib(puzzle[0]) puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.to_list_int) test_mode = IntcodeComputer(puzzle_input, 1).run_to_end() aoc.print_solution(1, test_mode) coordinates = IntcodeComputer(puzzle_input, 2).run_to_end() aoc.print_solution(1, coordinates)
moons = [] for line in puzzle_input: moon = ([0, 0, 0], [0, 0, 0]) coords = line[1:-1].split(', ') for coord in coords: key, value = coord.split('=') axis = 'xyz'.index(key) moon[0][axis] = int(value) moons.append(moon) for step in range(1000): for moon1 in moons: for moon2 in moons: if moon1 != moon2: for axis in (0, 1, 2): moon1[1][axis] += sign(moon2[0][axis] - moon1[0][axis]) for moon in moons: for axis in (0, 1, 2): moon[0][axis] += moon[1][axis] total_energy = 0 for moon in moons: potential_energy = abs(moon[0][0]) + abs(moon[0][1]) + abs(moon[0][2]) kinetic_energy = abs(moon[1][0]) + abs(moon[1][1]) + abs(moon[1][2]) total_energy += potential_energy * kinetic_energy aoc.print_solution(1, total_energy)
from lib.aoclib import AOCLib from intcode_computer import IntcodeComputer puzzle = (2019, 5) # Initialise the helper library aoc = AOCLib(puzzle[0]) puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.to_list_int) diagnostic_code_1 = IntcodeComputer(puzzle_input, 1).run_to_end() aoc.print_solution(1, diagnostic_code_1) diagnostic_code_2 = IntcodeComputer(puzzle_input, 5).run_to_end() aoc.print_solution(2, diagnostic_code_2)
aoc = AOCLib(puzzle[0]) # Get the puzzle input puzzle_input = aoc.get_puzzle_input(puzzle[1], AOCLib.lines_to_list) # print(puzzle_input) # Puzzle solution part 1 valid_passphrases = 0 for passphrase in puzzle_input: words = passphrase.split(' ') if len(words) == len(set(words)): valid_passphrases += 1 aoc.print_solution(1, valid_passphrases) # Puzzle solution part 2 valid_passphrases = 0 for passphrase in puzzle_input: words = [''.join(sorted(word)) for word in passphrase.split(' ')] if len(words) == len(set(words)): valid_passphrases += 1 aoc.print_solution(2, valid_passphrases)