def part1(): def is_valid(line): for field in REQ_FIELDS: if field not in line: return False return True return len([chunk for chunk in read_chunks("Input.txt") if is_valid(chunk)])
def get_tiles(): chunks = read_chunks('Input.txt') tiles = [ Tile(int(tile[tile.index('Tile ') + 5:tile.index(':\n')]), tile[tile.index(':\n') + 2:].split('\n')) for tile in chunks ] for tile in tiles: populate_edge_matches(tile, tiles) return tiles
def part2(): def get_field_index(line, field_name): try: return line.index(field_name) except ValueError: return -1 def parse_value(line, field_name, total_length): field_index = get_field_index(line, field_name) if field_index == -1: return False if len(line) < field_index + total_length: return False field_and_value = line[field_index: field_index + total_length] return field_and_value[field_and_value.index(':') + 1: len(field_and_value)] def valid_year(line, field_name, start_year, end_year): value = int(parse_value(line, field_name, 8)) if not value: return False if start_year <= value <= end_year: return True return False def valid_eye_colour(line): valid_colours = ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'] value = parse_value(line, 'ecl', 7) if value and value in valid_colours: return True return False def valid_hair_colour(line): valid_chars = '0123456789abcdef' value = parse_value(line, 'hcl', 11) if not value: return False value = value.rstrip() if len(value) == 7 \ and value[0] == '#' \ and all(c in valid_chars for c in value[1:len(value)]): return True return False def valid_passport_id(line): value = parse_value(line, 'pid', 14) if not value: value = parse_value(line, 'pid', 13) if not value: return False value = value.rstrip() if len(value) == 9 and value.isdigit(): return True return False def valid_height(line): field_index = get_field_index(line, 'hgt') if field_index == -1: return False value = line[field_index + 4:len(line)] if 'cm' in value: value = int(value[0:value.index('cm')]) if 150 <= value <= 193: return True elif 'in' in value: value = int(value[0:value.index('in')]) if 59 <= value <= 76: return True return False def is_valid(passport): valid = valid_year(passport, 'byr', 1920, 2002) \ and valid_year(passport, 'iyr', 2010, 2020) \ and valid_year(passport, 'eyr', 2020, 2030) \ and valid_eye_colour(passport) \ and valid_passport_id(passport) \ and valid_hair_colour(passport) \ and valid_height(passport) return valid return len([chunk for chunk in read_chunks("Input.txt") if is_valid(chunk)])
def part2(): def populate_possible_field_map(): for position in range(0, len(number_rows_ints[0])): all_possible_fields = set() for number in [ number_row[position] for number_row in number_rows_ints ]: this_number_fields = [] for valid_row in valids: field_name_and_ranges = get_valid_range(valid_row) ranges = field_name_and_ranges[1] if int(ranges[0][0]) <= int(number) <= int(ranges[0][1]) \ or int(ranges[1][0]) <= int(number) <= int(ranges[1][1]): this_number_fields.append(field_name_and_ranges[0]) if len(all_possible_fields) == 0: all_possible_fields = set(this_number_fields) else: all_possible_fields = set.intersection( all_possible_fields, this_number_fields) position_to_field_names[position] = list(all_possible_fields) def remove_definitely_known_fields(): for key in position_to_field_names.keys(): if len(position_to_field_names[key]) == 1: for other_key in position_to_field_names.keys(): if key == other_key: continue position_to_field_names[other_key] = [ entry for entry in position_to_field_names[other_key] if entry != position_to_field_names[key][0] ] chunks = read_chunks('Input.txt') valids = chunks[0].split('\n') number_rows = chunks[2].split('\n')[1:] completely_invalid = find_completely_invalid(valids, number_rows) remaining_number_rows = [ number_row for i, number_row in enumerate(number_rows) if i not in [valid[0] for valid in completely_invalid] ] number_rows_ints = [row.split(',') for row in remaining_number_rows] position_to_field_names = {} populate_possible_field_map() # Now go through the map, find positions for which we definitely know the field, and remove that # field from all the other positions. Keep doing that until all positions have only one possible field while len([ fields for fields in position_to_field_names.values() if len(fields) > 1 ]) > 0: remove_definitely_known_fields() departure_positions = [ key for key in position_to_field_names if 'departure' in position_to_field_names[key][0] ] my_rows = [ int(num_str) for num_str in chunks[1].split('\n')[1:][0].split(',') ] return math.prod([ num for index, num in enumerate(my_rows) if index in departure_positions ])
def part1(): chunks = read_chunks('Input.txt') valids = chunks[0].split('\n') number_rows = chunks[2].split('\n')[1:] return sum( [result[1] for result in find_completely_invalid(valids, number_rows)])
def part2(): return sum([get_all_yes_count(chunk) for chunk in read_chunks("Input.txt")])