Coverage for src\aoc2022\days\day13.py: 100%
41 statements
« prev ^ index » next coverage.py v7.0.0, created at 2022-12-23 05:19 +0000
« prev ^ index » next coverage.py v7.0.0, created at 2022-12-23 05:19 +0000
1from __future__ import annotations
3import functools
4import json
5from typing import List, Tuple, Union
7from src.aoc2022 import utils
9val_type = Union[List, int]
10pack_type = List[val_type]
13def parse_data_to_array(raw_data: str) -> List[Tuple[pack_type, pack_type]]:
14 """
15 Parse raw data into a list of packet tuples
17 :param raw_data: Raw data to parse into packets
18 :type raw_data: str
20 :return: a list of all packet pairs
21 :rtype: List[Tuple[List, List]]
22 """
23 packets = raw_data.split("\n\n")
25 packet_pairs = []
27 for packet in packets:
28 top_packet, bot_packet = packet.split("\n")
29 pair = (json.loads(top_packet), json.loads(bot_packet))
30 packet_pairs.append(pair)
32 return packet_pairs
35def element_is_equal(left_val: val_type, right_val: val_type) -> int:
36 """
37 Perform ternary comparison on two elements. Returns following:
38 - 1 if left_val smaller
39 - 0 if equal
40 - -1 if right_val smaller
42 :param left_val: left value for comparison
43 :type left_val: element_type
45 :param right_val: right value for comparison
46 :type right_val: element_type
48 :return: Ternary value for equality comparison
49 :rtype: int
50 """
51 if isinstance(left_val, int) and isinstance(right_val, int):
52 if left_val < right_val:
53 return 1
54 elif left_val > right_val:
55 return -1
56 else:
57 return 0
58 elif isinstance(left_val, list) and isinstance(right_val, list):
60 upper_bound = min(len(left_val), len(right_val))
62 for i in range(upper_bound):
63 is_eq = element_is_equal(left_val[i], right_val[i])
64 if is_eq == 1:
65 return 1
66 elif is_eq == -1:
67 return -1
68 else:
69 pass
71 l_size = len(left_val)
72 r_size = len(right_val)
74 return element_is_equal(l_size, r_size)
76 elif isinstance(left_val, list) and isinstance(right_val, int):
77 return element_is_equal(left_val, [right_val])
78 else:
79 return element_is_equal([left_val], right_val)
82def sort_packets(packets: List[pack_type]) -> List[pack_type]:
83 """
84 Sort packets using comparison function
86 :param packets: list of packets to sort
87 :type packets: List[pack_type]
89 :return: List of sorted packets
90 :rtype: List[pack_type]
91 """
92 packet_ordering_func = functools.cmp_to_key(element_is_equal)
93 sorted_packets = sorted(packets, key=packet_ordering_func, reverse=True)
95 return sorted_packets
98if __name__ == "__main__": # pragma: no cover
100 raw_data = utils.get_raw_data("./src/aoc2022/data/day13.txt")
101 parsed_data = parse_data_to_array(raw_data)
103 sum_ = 0
105 for i, pair in enumerate(parsed_data):
106 left_packet, right_packet = pair
107 res = element_is_equal(left_packet, right_packet)
108 if res == 1:
109 sum_ += i + 1
111 print(f"{sum_} pairs are in the correct order")
113 divider_packets: List = [[[2]], [[6]]]
114 all_packets = divider_packets
115 for left_packet, right_packet in parsed_data:
116 all_packets.append(left_packet)
117 all_packets.append(right_packet)
119 sorted_packets = sort_packets(all_packets)
121 packet_1_key = sorted_packets.index(divider_packets[0]) + 1
122 packet_2_key = sorted_packets.index(divider_packets[1]) + 1
124 print(f"The decoder key is {packet_1_key * packet_2_key}")