-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path13_distress-signal.py
executable file
·111 lines (84 loc) · 2.98 KB
/
13_distress-signal.py
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
#
# Copyright (c) 2022, xphade <github.com/xphade>
# SPDX-License-Identifier: MIT
import json
import time
from enum import Enum
from typing import Any, List, Tuple
from aoc_utils import get_input_path, print_elapsed_time
Packet = List[Any]
PacketPair = Tuple[Packet, Packet]
class Result(Enum):
VALID = 0
INVALID = 1
UNDECIDED = 2
def preprocess_input(contents: str) -> List[PacketPair]:
packet_pairs: List[PacketPair] = []
for pair in contents.split("\n\n"):
a, b = pair.splitlines()
packet_pairs.append((json.loads(a), json.loads(b)))
return packet_pairs
def compare_integers(lhs: int, rhs: int) -> Result:
if lhs == rhs:
return Result.UNDECIDED
return Result.VALID if lhs < rhs else Result.INVALID
def compare_lists(lhs: Packet, rhs: Packet) -> Result:
for left, right in zip(lhs, rhs):
if type(left) != type(right):
if type(left) is int:
left = [left]
else:
right = [right]
if type(left) is int and type(right) is int:
result = compare_integers(left, right)
if result == Result.UNDECIDED:
continue
return result
result = compare_lists(left, right)
if result == Result.UNDECIDED:
continue
return result
if len(lhs) == len(rhs):
return Result.UNDECIDED
return Result.VALID if len(lhs) < len(rhs) else Result.INVALID
def calculate_sum_of_valid_indices(packet_pairs: List[PacketPair]) -> int:
sum_of_indices = 0
for idx, (lhs, rhs) in enumerate(packet_pairs):
result = compare_lists(lhs, rhs)
if result == Result.VALID:
sum_of_indices += idx + 1
return sum_of_indices
def sort_packets(packets: List[Packet]):
"""Sorts the `packets` using an optimized bubble sort algorithm."""
n = len(packets)
while n > 1:
new_n = 0
for i in range(1, n):
if compare_lists(packets[i - 1], packets[i]) == Result.INVALID:
packets[i - 1], packets[i] = packets[i], packets[i - 1]
new_n = i
n = new_n
def find_decoder_key(sorted_packets: List[Packet]) -> int:
key = 1
for idx, packet in enumerate(sorted_packets):
if packet in [[[2]], [[6]]]:
key *= idx + 1
return key
def main():
data_path = get_input_path("Day 13: Distress Signal")
with open(data_path, "r") as file:
contents = file.read()
start = time.monotonic()
packet_pairs = preprocess_input(contents)
sum_of_valid_indices = calculate_sum_of_valid_indices(packet_pairs)
all_packets = [p for pair in packet_pairs for p in pair]
all_packets.extend([[[2]], [[6]]])
sort_packets(all_packets)
decoder_key = find_decoder_key(all_packets)
stop = time.monotonic()
print(f"Sum of valid indices: {sum_of_valid_indices}")
print(f"Decoder key: {decoder_key}")
print_elapsed_time(start, stop)
if __name__ == "__main__":
main()