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

1from __future__ import annotations 

2 

3import functools 

4import json 

5from typing import List, Tuple, Union 

6 

7from src.aoc2022 import utils 

8 

9val_type = Union[List, int] 

10pack_type = List[val_type] 

11 

12 

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 

16 

17 :param raw_data: Raw data to parse into packets 

18 :type raw_data: str 

19 

20 :return: a list of all packet pairs 

21 :rtype: List[Tuple[List, List]] 

22 """ 

23 packets = raw_data.split("\n\n") 

24 

25 packet_pairs = [] 

26 

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) 

31 

32 return packet_pairs 

33 

34 

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 

41 

42 :param left_val: left value for comparison 

43 :type left_val: element_type 

44 

45 :param right_val: right value for comparison 

46 :type right_val: element_type 

47 

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): 

59 

60 upper_bound = min(len(left_val), len(right_val)) 

61 

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 

70 

71 l_size = len(left_val) 

72 r_size = len(right_val) 

73 

74 return element_is_equal(l_size, r_size) 

75 

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) 

80 

81 

82def sort_packets(packets: List[pack_type]) -> List[pack_type]: 

83 """ 

84 Sort packets using comparison function 

85 

86 :param packets: list of packets to sort 

87 :type packets: List[pack_type] 

88 

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) 

94 

95 return sorted_packets 

96 

97 

98if __name__ == "__main__": # pragma: no cover 

99 

100 raw_data = utils.get_raw_data("./src/aoc2022/data/day13.txt") 

101 parsed_data = parse_data_to_array(raw_data) 

102 

103 sum_ = 0 

104 

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 

110 

111 print(f"{sum_} pairs are in the correct order") 

112 

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) 

118 

119 sorted_packets = sort_packets(all_packets) 

120 

121 packet_1_key = sorted_packets.index(divider_packets[0]) + 1 

122 packet_2_key = sorted_packets.index(divider_packets[1]) + 1 

123 

124 print(f"The decoder key is {packet_1_key * packet_2_key}")