From 2d6dd0e0748a427721bd0b23e7724fa964e38884 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Wed, 16 Dec 2020 07:46:55 +0100 Subject: [PATCH] day16: cleaner code --- day16.py | 120 +++++++++++++++++++++++-------------------------------- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/day16.py b/day16.py index 3ddcf8a..7b4317a 100644 --- a/day16.py +++ b/day16.py @@ -5,15 +5,15 @@ TEST_SOLUTION_PART1 = 71 TEST_SOLUTION_PART2 = 7 -def part1(test_mode=False): - my_input = aoclib.getInputAsArray(day=DAY, test=test_mode) - +def parse_input(to_parse): restraints = {} + my_ticket = [] other_tickets = [] - for i, line in enumerate(my_input): + for i, line in enumerate(to_parse): if not line: - other_tickets = my_input[i+5:] + my_ticket = list(map(int, to_parse[i+2].split(","))) + other_tickets = [list(map(int, ticket.split(","))) for ticket in to_parse[i+5:]] break field, limits = line.split(": ") @@ -22,94 +22,76 @@ def part1(test_mode=False): min_hi, max_hi = limit_hi.split("-") restraints[field] = [(int(min_low), int(max_low)), (int(min_hi), int(max_hi))] + return restraints, my_ticket, other_tickets + + +def is_valid_number(number, restraints): + for restraint in restraints.values(): + if restraint[0][0] <= number <= restraint[0][1] or restraint[1][0] <= number <= restraint[1][1]: + return True + + return False + + +def part1(test_mode=False): + my_input = aoclib.getInputAsArray(day=DAY, test=test_mode) + restraints, _, other_tickets = parse_input(my_input) + invalid_numbers = [] for ticket in other_tickets: - for number in ticket.split(","): - valid = False - number = int(number) - for field in restraints: - if restraints[field][0][0] <= number <= restraints[field][0][1] or \ - restraints[field][1][0] <= number <= restraints[field][1][1]: - valid = True - - break - - if not valid: + for number in ticket: + if not is_valid_number(number, restraints): invalid_numbers.append(number) return sum(invalid_numbers) -def part2(test_mode=False): - my_input = aoclib.getInputAsArray(day=DAY, test=test_mode) +def get_single_possible_positions(possible_positions): + single_possibilities = [] + while 1: + all_done = True + for field, possibilities in possible_positions.items(): + if len(possibilities) == 1: + possible_position = possibilities[0] + if possible_position not in single_possibilities: + all_done = False + single_possibilities.append(possible_position) + for check_field, check_positions in possible_positions.items(): + if possible_position in check_positions and len(check_positions) > 1: + possible_positions[check_field].remove(possible_position) - restraints = {} - possible_positions = {} - my_ticket = '' - other_tickets = [] - - for i, line in enumerate(my_input): - if not line: - my_ticket = my_input[i+2] - other_tickets = my_input[i+5:] + if all_done: break - field, limits = line.split(": ") - limit_low, limit_hi = limits.split(" or ") - min_low, max_low = limit_low.split("-") - min_hi, max_hi = limit_hi.split("-") - restraints[field] = [(int(min_low), int(max_low)), (int(min_hi), int(max_hi))] + return possible_positions + + +def part2(test_mode=False): + my_input = aoclib.getInputAsArray(day=DAY, test=test_mode) + restraints, my_ticket, other_tickets = parse_input(my_input) + possible_positions = {} + num_fields = len(my_ticket) - num_fields = len(my_ticket.split(',')) for field in restraints: - possible_positions[field] = [x for x in range(num_fields)] + possible_positions[field] = list(range(num_fields)) for ticket in other_tickets: invalid = False - for position, number in enumerate(ticket.split(",")): - valid = False - number = int(number) - for field in restraints: - if restraints[field][0][0] <= number <= restraints[field][0][1] or \ - restraints[field][1][0] <= number <= restraints[field][1][1]: - valid = True - - break - - if not valid: + for number in ticket: + if not is_valid_number(number, restraints): invalid = True break if invalid: continue - for position, number in enumerate(ticket.split(",")): - number = int(number) - for field in restraints: - if not restraints[field][0][0] <= number <= restraints[field][0][1] and \ - not restraints[field][1][0] <= number <= restraints[field][1][1]: + for position, number in enumerate(ticket): + for field, restraint in restraints.items(): + if not restraint[0][0] <= number <= restraint[0][1] and not restraint[1][0] <= number <= restraint[1][1]: possible_positions[field].remove(position) - single_possibilities = [] - while 1: - all_done = True - for field, possibilities in possible_positions.items(): - possible_position = possibilities[0] - if len(possibilities) == 1 and possible_position not in single_possibilities: - all_done = False - single_possibilities.append(possible_position) - for check_field in possible_positions: - try: - if len(possible_positions[check_field]) > 1: - possible_positions[check_field].remove(possible_position) - except ValueError: - pass - - if all_done: - break - + possible_positions = get_single_possible_positions(possible_positions) answer = 1 - my_ticket = [int(x) for x in my_ticket.split(",")] for field in restraints: if field.startswith('departure'): answer *= my_ticket[possible_positions[field][0]]