def main():
    cube = Cube(read_full_text(2020, 17), 4)

    for _ in range(6):
        cube.simulate_cycle()

    print(cube.count_active())
Exemple #2
0
def main():
    text = read_full_text(2020, 19)

    [rules, messages] = text.split("\n\n")
    rules = rules.splitlines()
    # Need to slightly change formatting so precedence rules work.
    # Space cannot be both an operator and space - it just doesn't make sense,
    # so remove spaces around |, which are just for display.
    rules = {
        int(index): rule.replace(" | ", "|").strip()
        for [index, rule] in [rule.split(":") for rule in rules]
    }
    messages = messages.splitlines()

    lexer = RuleLexer()
    parser = RuleParser()

    for rule in rules:
        rules[rule] = parser.parse(lexer.tokenize(rules[rule]))

    regex = re.compile("^" + generate_regex(rules, 0) + "$")
    count = 0

    for message in messages:
        if regex.match(message):
            count += 1

    print(count)
def main():
    text = read_full_text(2020, 16)

    fields = get_fields(text)
    nearby_tickets = get_tickets("nearby", text)
    your_ticket = get_tickets("your", text)[0]

    invalid_values = []
    all_fields = set(chain.from_iterable(fields.values()))

    valid_tickets = []

    for ticket in nearby_tickets:
        if all([value in all_fields for value in ticket]):
            valid_tickets.append(ticket)

    # List of each column of the CSV.
    column_values = list(zip(*valid_tickets))
    # Dictionary of field name to potential indices.
    field_indices = {
        field: set(range(len(valid_tickets[0])))
        for field in fields.keys()
    }

    # Remove column numbers for each field that does not match the ranges.
    for i in range(len(column_values)):
        for field, range_ in fields.items():
            values_in_range = [
                value for value in column_values[i] if value in range_
            ]

            if len(values_in_range) != len(column_values[i]):
                field_indices[field].remove(i)

    # Whiddle down indices by setting an int for any field that has only one possible index,
    # then remove that index from all other fields, since it can only be used once.
    #
    # Repeat until all fields have been resolved.
    while True:
        for field, values in field_indices.items():
            if isinstance(values, set) and len(values) == 1:
                field_indices[field] = list(values)[0]

                for values_ in field_indices.values():
                    if isinstance(values_,
                                  set) and field_indices[field] in values_:
                        values_.remove(field_indices[field])

        if all(isinstance(_values, int) for _values in field_indices.values()):
            break

    print(
        reduce(
            mul,
            [
                your_ticket[index] for field, index in field_indices.items()
                if field.startswith("departure")
            ],
        ))
def main():
    text = read_full_text(2020, 19)

    [rules, messages] = text.split("\n\n")
    rules = rules.splitlines()
    # Need to slightly change formatting so precedence rules work.
    # Space cannot be both an operator and space - it just doesn't make sense,
    # so remove spaces around |, which are just for display.
    rules = {
        int(index): rule.replace(" | ", "|").strip()
        for [index, rule] in [rule.split(":") for rule in rules]
    }
    messages = messages.splitlines()

    lexer = RuleLexer()
    parser = RuleParser()

    for rule in rules:
        rules[rule] = parser.parse(lexer.tokenize(rules[rule]))

    rule_res = {}
    for rule in sorted(rules.keys()):
        if rule == 0 or rule == 8 or rule == 11:
            continue
        rule_res[rule] = generate_regex(rules, rule)

    # Pattern 8 is just pattern 42 one or more times
    rule_res[8] = f"(?:{rule_res[42]}+)"
    # Pattern 11 needs to specifically use a recursive regex
    rule_res[
        11] = f"(?:({rule_res[42]}{rule_res[31]}|{rule_res[42]}(?-1){rule_res[31]}))"
    # Now that we have patterns 8 and 11 we can build pattern 0
    rule_res[0] = f"^(?:{rule_res[8]}{rule_res[11]})$"

    count = 0

    for message in messages:
        # Need to use perl because Python does not have recursive regex
        # (could use the regex module but don't feel like it)
        proc = subprocess.run(
            f"perl -e 'print \"{message}\" =~ /{rule_res[0]}/ ? 1 : 0'",
            capture_output=True,
            shell=True,
        )
        if int(proc.stdout) == 1:
            count += 1

    print(count)
Exemple #5
0
def main():
    text = read_full_text(2020, 16)

    fields = get_fields(text)
    nearby_tickets = get_tickets("nearby", text)
    your_tickets = get_tickets("your", text)

    invalid_values = []
    all_values = list(chain.from_iterable(nearby_tickets))
    all_fields = set(chain.from_iterable(chain.from_iterable(fields.values())))

    for value in all_values:
        if value not in all_fields:
            invalid_values.append(value)

    print(sum(invalid_values))
def main():
    text = read_full_text(2020, 20)
    tiles = {
        int(id_): Tile(tile)
        for id_, tile in re.findall(r"Tile (\d+):\n([\.#\n]+)", text)
    }

    matches = defaultdict(lambda: 0)

    for tile_a, tile_b in product(tiles, tiles):
        if tile_a == tile_b:
            continue

        matches[tile_a] += len(tiles[tile_a].match_tile(tiles[tile_b]))

    print(reduce(mul, (id_ for id_, matches in matches.items() if matches == 2)))
def main():
    text = read_full_text(2020, 20)
    tiles = {
        int(id_): Tile(tile)
        for id_, tile in re.findall(r"Tile (\d+):\n([\.#\n]+)", text)
    }

    matches = defaultdict(lambda: 0)

    for tile_a, tile_b in product(tiles, tiles):
        if tile_a == tile_b:
            continue

        matches[tile_a] += len(tiles[tile_a].match_tile(tiles[tile_b]))

    corners = [tiles[id_] for id_, matches in matches.items() if matches == 2]

    corners[0].extend_corner(tiles.values())
Exemple #8
0
def get_passenger_groups():
    return (group.strip().split("\n")
            for group in read_full_text(2020, 6).split("\n\n"))
def get_passport_chunks() -> Iterator[str]:
    """Read the input text into individual passport chunks."""
    text = read_full_text(2020, 4)
    return (re.sub(r"\s+", " ", chunk) for chunk in text.split("\n\n"))