예제 #1
0
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}')
예제 #2
0
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}'
    )
예제 #3
0
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}')
예제 #4
0
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)}'
    )
예제 #5
0
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}')
예제 #6
0
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}')
예제 #7
0
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())}')
예제 #8
0
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}')
예제 #9
0
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)}')
예제 #10
0
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)
예제 #11
0
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)}'
        )
예제 #12
0
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)}')
예제 #13
0
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()}')
예제 #14
0
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}')
예제 #15
0
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)
예제 #16
0
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}')
예제 #17
0
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}')
예제 #18
0
                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):
예제 #19
0
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)