summaryrefslogtreecommitdiffstats
path: root/day13/__init__.py
blob: d9fd9f2cb99d7ef5bf229ace68e7fcc2180e93d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -*- coding: utf-8 -*-
import json
from abc import ABC
from functools import cmp_to_key, reduce
from typing import Iterator, Any, List, Tuple, Union

from aoc import BaseAssignment


Packet = Union[List[int], int, List["Packet"]]


class Assignment(BaseAssignment, ABC):
    def compare_pair(self, pair: Tuple[Packet, Packet]):
        packet_a, packet_b = pair

        if isinstance(packet_a, int) and isinstance(packet_b, int):
            diff = packet_b - packet_a
            return diff / abs(diff) if diff != 0 else 0

        if isinstance(packet_a, list) and isinstance(packet_b, int):
            packet_b = [packet_b]

        if isinstance(packet_b, list) and isinstance(packet_a, int):
            packet_a = [packet_a]

        try:
            for sub_pair in zip(packet_a, packet_b, strict=True):
                comparison = self.compare_pair(sub_pair)

                if comparison != 0:
                    return comparison
        except ValueError:
            return self.compare_pair((len(packet_a), len(packet_b)))

        return 0


class AssignmentOne(Assignment):
    example_result = 13

    def pairs(self, input: Iterator[str]):
        while True:
            yield (json.loads(next(input)), json.loads(next(input)))

            try:
                next(input)
            except StopIteration:
                break

    def run(self, input: Iterator) -> Any:
        return sum(
            index
            for index, pair in enumerate(self.pairs(input), start=1)
            if self.compare_pair(pair) > 0
        )


class AssignmentTwo(Assignment):
    example_result = 140

    def packets(self, input: Iterator[str]):
        for item in input:
            if item == "":
                continue

            yield json.loads(item)

    def run(self, input: Iterator) -> Any:
        packets = sorted(
            [[[2]], [[6]], *self.packets(input)],
            key=cmp_to_key(lambda a, b: self.compare_pair((a, b))),
            reverse=True,
        )

        return reduce(
            lambda o, i: o * i,
            [
                index
                for index, packet in enumerate(packets, start=1)
                if packet
                in (
                    [[2]],
                    [[6]],
                )
            ],
        )