Beispiel #1
0
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)])
Beispiel #2
0
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
Beispiel #3
0
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)])
Beispiel #4
0
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
    ])
Beispiel #5
0
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)])
Beispiel #6
0
def part2():
    return sum([get_all_yes_count(chunk) for chunk in read_chunks("Input.txt")])