Advent of Code 2024 - Day 11

# Part 1

 1from __future__ import annotations
 2
 3import math
 4import dataclasses
 5import typing
 6
 7@dataclasses.dataclass
 8class Node:
 9    value: int
10    nxt: Node | None = None
11
12
13def get_data(path: str) -> typing.Iterator[int]:
14    with open(path) as f:
15        yield from (int(x) for x in f.read().strip().split())
16
17def blink(node):
18    while node:
19        match node.value:
20            case 0:
21                node.value = 1
22            case it if int(math.log(it, 10)) % 2 == 1:
23                digits = int(math.log(it, 10)) + 1
24                leading_digits = int(str(it)[:digits // 2])
25                trailing_digits = int(str(it)[digits // 2:])
26
27                new_node = Node(trailing_digits, node.nxt)
28                node.nxt = new_node
29                node.value = leading_digits
30                node = new_node
31            case _:
32                node.value *= 2024
33        node = node.nxt
34
35def main(data: typing.Iterator[int]) -> int:
36    front_node = Node(next(data))
37    last_node = front_node
38    for datum in data:
39        last_node.nxt = Node(datum)
40        last_node = last_node.nxt
41
42    for _ in range(25):
43        blink(front_node)
44
45    node_count = 0
46    node = front_node
47    while node:
48        node_count += 1
49        node = node.nxt
50
51    return node_count
52
53
54if __name__ == "__main__":
55    print(main(get_data("day_11_input.txt")))

# Part 2

 1from __future__ import annotations
 2
 3import math
 4import collections
 5import typing
 6
 7def get_data(path: str) -> typing.Iterator[int]:
 8    with open(path) as f:
 9        yield from (int(x) for x in f.read().strip().split())
10
11def blink(counter: dict[int, int]) -> dict[int, int]:
12    next_counter = collections.defaultdict(int)
13    for k, count in counter.items():
14        match k:
15            case 0:
16                next_counter[1] += count
17            case it if int(math.log(it, 10)) % 2 == 1:
18                digits = int(math.log(it, 10)) + 1
19                leading_digits = int(str(it)[:digits // 2])
20                trailing_digits = int(str(it)[digits // 2:])
21                next_counter[leading_digits] += count
22                next_counter[trailing_digits] += count
23            case _:
24                next_counter[k * 2024] += count
25
26    return next_counter
27
28def main(data: typing.Iterator[int]) -> int:
29    counter = collections.defaultdict(int)
30
31    for datum in data:
32        counter[datum] += 1
33
34    for _ in range(75):
35        counter = blink(counter)
36
37    return sum(counter.values())
38
39
40if __name__ == "__main__":
41    print(main(get_data("day_11_input.txt")))