Esempio n. 1
0
def run() -> (int, int):

    tiles, tile_edges = {}, {}
    for tile_info in read_as.groups("input/20.txt"):
        tile_id = int(re.search("Tile ([0-9]+):", tile_info[0]).groups()[0])
        tile = tile_info[1:]
        tiles[tile_id] = tile

        edges = [
            top_row(tile),
            right_col(tile),
            bottom_row(tile),
            left_col(tile)
        ]
        tile_edges[tile_id] = edges

    matching_edges = set()
    matches = defaultdict(lambda: defaultdict(list))
    for t, other_t in it.product(tile_edges, repeat=2):
        if other_t != t:
            for i in range(len(tile_edges[t])):
                edge = tile_edges[t][i]
                for j in range(len(tile_edges[other_t])):
                    other_edge = tile_edges[other_t][j]
                    if edge == other_edge or edge == other_edge[::-1]:
                        matches[t][i] = other_t
                        matching_edges.add(edge)

    corners = [tile for tile in tiles if len(matches[tile]) == 2]
    prod_corners = math.prod(c for c in corners)

    # P2
    grid = pop_grid(corners[0], tiles, matching_edges, matches)

    n = int(math.sqrt(len(tiles)))

    grid_stripped = []
    for r in range(n):
        for sub_r in range(1, len(grid[(0, 0)][1]) - 1):
            row_str = ""
            for c in range(n):
                row_str += grid[(r, c)][1][sub_r][1:-1]
            grid_stripped.append(row_str)

    monster = [
        "                  # ", "#    ##    ##    ###", " #  #  #  #  #  #   "
    ]

    rollover = len(grid_stripped[0]) - len(monster[0])
    monster_regex = "(?=" + ("." * rollover).join(monster).replace(' ',
                                                                   ".") + ")"

    grid_rots = rot_and_flip_while_cond(grid_stripped, {lambda x: True})
    max_monsters = max(
        [len(re.findall(monster_regex, "".join(g))) for g in grid_rots])

    roughness = "".join(grid_stripped).count(
        "#") - max_monsters * monster_regex.count("#")

    return (prod_corners, roughness)
Esempio n. 2
0
def run() -> (int, int):
    groups = read_as.groups("input/19.txt")
    rules = {}
    for line in groups[0]:
        rule_id, rule_contents = line.split(':')

        base_rule = re.search(r"\"(.*)\"", rule_contents)
        if base_rule:
            letter = base_rule.groups()[0]
            rules[rule_id] = letter
        else:
            rules[rule_id] = "( " + rule_contents.strip() + " )"

    rules_p1 = rules_to_regex(deepcopy(rules))

    rules_p2 = deepcopy(rules)
    rules_p2["8"] = "( 42 )+"
    # dirty hack
    rules_p2[
        "11"] = "( 42 31 | 42 42 31 31 | 42 42 42 31 31 31 | 42 42 42 42 31 31 31 31 | 42 42 42 42 42 31 31 31 31 31 | 42 42 42 42 42 42 31 31 31 31 31 31 | 42 42 42 42 42 42 42 31 31 31 31 31 31 31 | 42 42 42 42 42 42 42 42 31 31 31 31 31 31 31 31 | 42 42 42 42 42 42 42 42 42 31 31 31 31 31 31 31 31 31 | 42 42 42 42 42 42 42 42 42 42 31 31 31 31 31 31 31 31 31 31 )"
    rules_p2 = rules_to_regex(rules_p2)

    p1 = sum([
        re.fullmatch(rules_p1["0"].replace(" ", ''), message) is not None
        for message in groups[1]
    ])
    p2 = sum([
        re.fullmatch(rules_p2["0"].replace(" ", ''), message) is not None
        for message in groups[1]
    ])

    return (p1, p2)
Esempio n. 3
0
def run() -> (int, int):
    answer_sets = [list(map(set, group)) for group in read_as.groups("input/6.txt")]

    sum_any, sum_all = 0, 0
    for answer_set in answer_sets:
        sum_any += len(set.union(*answer_set))
        sum_all += len(set.intersection(*answer_set))

    return(sum_any, sum_all)
Esempio n. 4
0
def run() -> (int, int):

    lines = [" ".join(group) for group in read_as.groups("input/4.txt")]
    passports = [
        dict(val.split(":") for val in line.split()) for line in lines
    ]
    all_fields = [p for p in passports if has_fields(p)]
    valid_fields = [p for p in passports if has_valid_fields(p)]

    return len(all_fields), len(valid_fields)
Esempio n. 5
0
def run() -> (int, int):
    groups = read_as.groups("input/22.txt")
    player_cards = [int(n) for n in groups[0][1:]]
    crab_cards = [int(n) for n in groups[1][1:]]

    _, winner_hand_p1 = recursive_combat(player_cards, crab_cards, {}, False)
    _, winner_hand_p2 = recursive_combat(player_cards, crab_cards, {}, True)

    score_p1 = sum([(i + 1) * n for (i, n) in enumerate(winner_hand_p1[::-1])])
    score_p2 = sum([(i + 1) * n for (i, n) in enumerate(winner_hand_p2[::-1])])
    return (score_p1, score_p2)
Esempio n. 6
0
def run() -> (int, int):
    rules, my_ticket, other_tickets = read_as.groups("input/16.txt")

    ruleset = {}
    for rule in rules:
        name, a, b, c, d = re.search(r"([a-z ]+): (\d+)-(\d+) or (\d+)-(\d+)",
                                     rule).groups()
        ruleset[name] = [range(int(a), int(b) + 1), range(int(c), int(d) + 1)]

    matches_rule = lambda field, ranges: int(field) in ranges[0] or int(
        field) in ranges[1]
    field_valid = lambda field: any(
        matches_rule(field, ranges) for ranges in ruleset.values())
    ticket_valid = lambda ticket: all(
        field_valid(field) for field in ticket.split(","))

    scanning_rate = sum(
        int(field) for ticket in other_tickets[1:]
        for field in ticket.split(",") if not field_valid(field))

    # P2
    valid_other_tickets = [
        ticket for ticket in other_tickets[1:] if ticket_valid(ticket)
    ]

    rule_indices = {
        rule: set(i for i in range(len(ruleset)))
        for rule in ruleset
    }
    for valid_ticket in valid_other_tickets:
        for (index, field) in enumerate(valid_ticket.split(",")):
            for rule in ruleset:
                if not (matches_rule(field, ruleset[rule])):
                    rule_indices[rule].remove(index)

    known_indices = {}
    for r, v in sorted(rule_indices.items(), key=lambda x: len(x[1])):
        known_indices[r] = {x
                            for x in v
                            if x not in known_indices.values()}.pop()

    my_fields = [int(field) for field in my_ticket[1].split(",")]
    prod_of_fields = prod([
        my_fields[index] for rule, index in known_indices.items()
        if rule.startswith("departure")
    ])

    return (scanning_rate, prod_of_fields)