def solve_day_eleven(): input_data = read_aoc_input_file('Day_11', return_as_string=True, test_input=False) mapping = {'.': -1, 'L': 0, '#': 1} kernel = [[1, 1, 1], [1, 0, 1], [1, 1, 1]] current_seating = np.array([[mapping.get(c) for c in line] for line in input_data]) previous_seating = np.empty(current_seating.shape) while not np.array_equal(current_seating, previous_seating): previous_seating = current_seating neighbourhood = convolve(np.where(current_seating == -1, 0, current_seating), kernel, mode='constant') current_seating = np.where( current_seating == -1, mapping.get('.'), np.where( neighbourhood >= 4, mapping.get('L'), np.where(neighbourhood == 0, mapping.get('#'), current_seating))) occupied_at_equillibrium = sum(sum(current_seating == mapping.get('#'))) print( f'Numper of occupied seats at equilibrium: {occupied_at_equillibrium}')
def solve_day_eight(): input_data = read_aoc_input_file('Day_8', return_as_string=True) instruction_regex = r'(\w{3}) ([\+-])(\d+)' instruction_set = [] for line in input_data: line_instruction = re.findall(instruction_regex, line) instruction_set.append(list(line_instruction[0])) part_one_answer, _ = execute_code(instruction_set) for line_num, (instruction, _, _) in enumerate(instruction_set): if instruction in ['jmp', 'nop']: instruction_set[line_num][ 0] = 'jmp' if instruction == 'nop' else 'nop' accumulator, no_loop = execute_code(instruction_set) instruction_set[line_num][0] = instruction if no_loop: part_two_answer = accumulator break print( f'Accumulator output before loop with original code: {part_one_answer}' ) print( f'Accumulator output after changing line {line_num}: {part_two_answer}' )
def solve_day_two(): input_path = os.path.join ('C:/', 'Users', 'andre', 'Documents', 'AdventOfCode', 'Day_2', 'input.txt') input_data = read_aoc_input_file('Day_2', return_as_string=True) valid_password_count_policy_1 = 0 valid_password_count_policy_2 = 0 for password_line in input_data: policy, letter, password = password_line.split(' ') min_letter_count = int(re.search(r'^\d{1,2}', policy).group(0)) max_letter_count = int(re.search(r'\d{1,2}$', policy).group(0)) letter = letter.strip(':') # Task 1 if password.count(letter) in range(min_letter_count, max_letter_count+1): valid_password_count_policy_1 += 1 # Task 2 first_letter_idx = min_letter_count - 1 second_letter_idx = max_letter_count - 1 if (password[first_letter_idx] == letter) != (password[second_letter_idx] == letter): # XOR valid_password_count_policy_2 += 1 print(f'Valid password count using policy 1: {valid_password_count_policy_1}') print(f'Valid password count using policy 2: {valid_password_count_policy_2}')
def solve_day_nine(): input_data = read_aoc_input_file('Day_9', return_as_string=False, test_input=False) preamble_length = 25 for (i, num) in enumerate(input_data): if i < preamble_length: continue current_preamble = input_data[i - preamble_length:i] preamble_sums = [sum(g) for g in combinations(current_preamble, 2)] if num not in preamble_sums: print(f'{num} not in preamble at position {i}') break for chunk_size in range(2, 150): for start_idx in range(0, i - chunk_size): relevant_input = input_data[start_idx:i] sublists = list(chunks(relevant_input, chunk_size)) sublist_sums = [sum(l) for l in sublists] if num in sublist_sums: key_list = sublists[sublist_sums.index(num)] break print( f'List of numbers that sum to input: {key_list}. Sum of min an max: {min(key_list) + max(key_list)}' )
def solve_day_four(): input_data = read_aoc_input_file('Day_4', return_as_string=True) passport_entries = format_passport_inputs(input_data) mandatory_fields = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'] valid_passport_count_task_1 = 0 valid_passport_count_task_2 = 0 invalid_passport_count_task_1 = 0 invalid_passport_count_task_2 = 0 for entry in passport_entries.values(): if all([k in entry.keys() for k in mandatory_fields]): valid_passport_count_task_1 += 1 # Additional checks for task 2. valid_passport_task_2 = check_fields(entry) if valid_passport_task_2: valid_passport_count_task_2 += 1 else: invalid_passport_count_task_2 += 1 else: invalid_passport_count_task_1 += 1 invalid_passport_count_task_2 += 1 print(f'Total number of passports checked: {len(passport_entries)}') print('-'*50) print(f'Passports with complete data for task 1: {valid_passport_count_task_1}') print(f'Passports with missing data for task 1: {invalid_passport_count_task_1}') print('-'*50) print(f'Passports with complete data for task 2: {valid_passport_count_task_2}') print(f'Passports with missing data for task 2: {invalid_passport_count_task_2}')
def solve_day_10(): input_data = read_aoc_input_file('Day_10', return_as_string=False, test_input=False) # Task 1 input_data = sorted(input_data) all_jolts = [0] + input_data + [max(input_data) + 3] rating_diffs = np.diff(all_jolts) one_diff = len(rating_diffs[rating_diffs == 1]) three_diff = len(rating_diffs[rating_diffs == 3]) print( f'Product of the count of "one-diff" and "three-diff" adapters: {one_diff*three_diff}' ) # Task 2 group_splits = [0] + [ idx + 1 for idx, val in enumerate(rating_diffs) if val == 3 ] # Find where the jump between adapter is the maximum 3 jolts adapter_groups = [ all_jolts[i:j] for i, j in zip(group_splits, group_splits[1:]) ] # Split adapters into groups where we can "reach" the next group # From each group we can choose to include a subset of the adapters according to a tribonacci sequence. tribonacci_mapping = {1: 1, 2: 1, 3: 2, 4: 4, 5: 7} possibilities = 1 for group in adapter_groups: possibilities *= tribonacci_mapping.get(len(group)) print(f'Number of possible adapter configurations: {possibilities}')
def solve_day_fourteen(is_part_two=False): input_data = read_aoc_input_file('Day_14', return_as_string=True) memory = {} mem_regex = r'\w+\[(\d+)\]' for line in input_data: instruction, value = line.split(' = ') if 'mask' in instruction: mask = value else: mem_address = re.match(mem_regex, instruction).groups()[0] if is_part_two: mem_address = '{:036b}'.format(int(mem_address)) val_as_int = int(value) output_value = ''.join([ adr if m == '0' else m for m, adr in zip(mask, mem_address) ]) for address in get_floating_addresses(output_value): memory[int(address, base=2)] = val_as_int else: val_as_bytes = '{:036b}'.format(int(value)) output_value = ''.join([ val if mem == 'X' else mem for mem, val in zip(mask, val_as_bytes) ]) memory[mem_address] = int(output_value, base=2) print(f'Sum of values in memory: {sum(memory.values())}')
def solve_day_one(target_sum: int = 2020, group_size: int = 2): input_data = read_aoc_input_file('Day_1', return_as_string=False) groups = combinations(input_data, group_size) target_group = [g for g in groups if sum(g) == target_sum] prod = listprod(target_group[0]) print(f'Found addends: {target_group}') print(f'Product of addends for group size {group_size}: {prod}')
def solve_day_six(): input_data = read_aoc_input_file('Day_6', return_as_string=True) input_groups = format_input_groups(input_data) group_counts = [len(set(''.join(g))) for g in input_groups.values()] # Task 1 common_answer_count = [(sum([all(v in g for g in group) for v in set(''.join(group))])) for group in input_groups.values()] # Task 2 print(f'Number of questions where anyone answered yes: {sum(group_counts)}') print(f'Number of questions where everyone answered yes: {sum(common_answer_count)}')
def solve_day_thirteen(): input_data = read_aoc_input_file('Day_13', return_as_string=True, test_input=False) earliest_departure = int(input_data[0]) bus_lines = [int(b) for b in input_data[1].split(',') if b != 'x'] bus_schedule = input_data[1].split(',') task_1(earliest_departure, bus_lines) task_2(bus_schedule)
def solve_day_eighteen(): input_data = read_aoc_input_file('Day_18', return_as_string=True) input_data = [expr.replace(' ', '') for expr in input_data] for task in [(1, False), (2, True)]: results = [] for expr in input_data: rpn = convert_to_rpn(expr, task[1]) results.append(evaluate_rpn(rpn)) print( f'Sum of all expression evaluations using precedence in task {task[0]}: {sum(results)}' )
def solve_day_five(): input_data = read_aoc_input_file('Day_5', return_as_string=True) seat_ids = {} for boarding_code in input_data: row_code = boarding_code[0:7] col_code = boarding_code[7:] seat_row = binary_seat_search(row_code) seat_col = binary_seat_search(col_code) seat_ids[boarding_code] = seat_row * 8 + seat_col sorted_ids = sorted([v for v in seat_ids.values()]) id_diff = np.diff(sorted_ids) skipped_id_idx = id_diff > 1 skipped_id = list(compress(sorted_ids, skipped_id_idx))[0] + 1 print(f'Maximum seat ID: {int(sorted_ids[-1])}') print(f'Own seat location: {int(skipped_id)}')
def part_two(): input_data = read_aoc_input_file('Day_11', return_as_string=True, test_input=False) data = parse_raw(input_data) floor, no_floor = data == FLOOR, data != FLOOR h, w = data.shape last = None seats = neighbors = data.copy() ys, xs = np.mgrid[:h, :w] ys, xs = ys[no_floor], xs[no_floor] while seats.tobytes() != last: last = seats.tobytes() neighbors[no_floor] = seen(ys, xs, seats) seats = np.where(neighbors >= 5, EMPTY, np.where(neighbors == 0, OCCUPIED, seats)) print(f'{(seats == OCCUPIED).sum()}')
def solve_day_seventeen(): # NB: To solve for task 1, remove first dimension of all arrays and remove loop over "w" input_data = read_aoc_input_file('Day_17', return_as_string=True, test_input=False) mapping = {'.': 0, '#': 1} kernel = np.ones((3, 3, 3, 3)) kernel[1, 1, 1, 1] = 0 initial_state = np.array([[mapping.get(c) for c in line] for line in input_data]) surrounding_states = np.zeros(( 3, 3, ) + initial_state.shape) surrounding_states[1, 1, :, :] = initial_state current_state = surrounding_states previous_state = np.empty(current_state.shape) for i in range(0, 6): previous_state = current_state next_state = np.pad(previous_state, 1) surroundings = convolve(next_state, kernel, mode='constant') for w in range(next_state.shape[0]): for z in range(next_state.shape[1]): for x in range(next_state.shape[2]): for y in range(next_state.shape[3]): if next_state[w, z, x, y] == 1 and ( surroundings[w, z, x, y] == 2 or surroundings[w, z, x, y] == 3): next_state[w, z, x, y] = 1 elif next_state[w, z, x, y] == 0 and surroundings[w, z, x, y] == 3: next_state[w, z, x, y] = 1 else: next_state[w, z, x, y] = 0 current_state = next_state num_active_cubes = np.sum(current_state) print(f'Number of active cubes after six cycles: {num_active_cubes}')
def solve_day_sixteen(): input_data = read_aoc_input_file('Day_16', return_as_string=True) regex = r'([\d-]*) or ([\d-]*)' valid_ranges = {} rules = input_data[:20] tickets = [int(t) for r in input_data[25:] for t in r.split(',')] for rule in rules: ranges = re.findall(regex, rule) for interval in ranges[0]: limits = interval.split('-') valid_ranges([int(limits[0]), int(limits[1])]) tser = 0 for ticket_value in tickets: if not any([ticket_value in range(r[0], r[1]) for r in valid_ranges]): tser += ticket_value print(tser)
def solve_day_seven(): input_data = read_aoc_input_file('Day_7', return_as_string=True) base_bag = 'shiny gold' bag_matcher = r'(\d+) (\w* \w*)' bag_dict = {} for line in input_data: top_bag = re.match(r'(\w* \w*)', line)[0] bag_contents = { bag: int(count) for count, bag in re.findall(bag_matcher, line) } bag_dict[top_bag] = bag_contents can_hold_gold_bag = len(set(recursive_contents( base_bag, bag_dict))) - 1 # Remove gold bag itself bag_content_count = count_bags(base_bag, bag_dict) print(f'Contains {base_bag} bag: {can_hold_gold_bag}') print(f'Bag contents of {base_bag} bag: {bag_content_count}')
def solve_day_three(row_steps, col_steps): input_data = read_aoc_input_file('Day_3', return_as_string=True) row_length = len(input_data[0]) step_count = 0 num_trees = [0] * len(row_steps) for i, (row_step, col_step) in enumerate(zip(row_steps, col_steps)): row_idx = 0 col_idx = 0 while row_idx < len(input_data) - 1: col_idx = (col_idx + col_step) % row_length row_idx += row_step if input_data[row_idx][col_idx] == '#': num_trees[i] += 1 prod = listprod(num_trees) print(f'Number of trees encountered on different slopes: {num_trees}') print(f'Solution task 1: {num_trees[1]}') print(f'Solution task 2: {prod}')
np.where(neighbourhood == 0, mapping.get('#'), current_seating))) occupied_at_equillibrium = sum(sum(current_seating == mapping.get('#'))) print( f'Numper of occupied seats at equilibrium: {occupied_at_equillibrium}') def parse_raw(raw): trans = {".": FLOOR, "L": EMPTY} return np.array([[trans[char] for char in line] for line in raw]) FLOOR, EMPTY, OCCUPIED = -1, 0, 1 input_data = read_aoc_input_file('Day_11', return_as_string=True, test_input=False) data = parse_raw(input_data) floor, no_floor = data == FLOOR, data != FLOOR h, w = data.shape @lru_cache(maxsize=None) def neighborhood(y, x): ys, xs = [], [] for y_step, x_step in product((-1, 0, 1), repeat=2): if y_step == x_step == 0: continue for i in count(1): cell_y, cell_x = y + i * y_step, x + i * x_step if cell_y not in range(0, h) or cell_x not in range(0, w):
def solve_day_twelve(): input_data = read_aoc_input_file('Day_12', return_as_string=True, test_input=False) task_1(input_data) task_2(input_data)