/ 13.py
13.py
 1  #!/usr/bin/python3
 2  
 3  # run it as
 4  # ./13.py inputs/13 [--one | --two] [--debug]
 5  
 6  import sys
 7  import logging
 8  from itertools import zip_longest
 9  from functools import total_ordering
10  import math
11  
12  if '--debug' in sys.argv:
13      logging.basicConfig(level=logging.DEBUG)
14  logger = logging.getLogger()
15  
16  EXTRA_PACKETS = [[[2]], [[6]]]
17  
18  def gimme_pairs():
19      with open(sys.argv[1]) as f:
20          return zip(*[(eval(line.strip()) for line in f.readlines() if line.strip())]*2)
21  
22  def gimme_packets():
23      with open(sys.argv[1]) as f:
24          return (eval(line.strip()) for line in f.readlines() if line.strip())
25  
26  
27  @total_ordering
28  class Packet:
29      def __init__(self, value):
30          self.value = value
31  
32      def __eq__(self, other):
33          # is this even approved by Vatican?
34          return str(self.value) == str(other.value)
35  
36      def __lt__(self, other):
37          comp = compare(self.value, other.value)
38          assert comp is not None
39          return comp
40  
41      def __repr__(self):
42          return repr(self.value)
43  
44  
45  def compare(left, right):
46      """
47      there probably is some cool math optimization to avoid all these steps
48      """
49      logger.info(f'left is {left}, right is {right}')
50      if left is None:
51          return True
52      elif right is None:
53          return False
54      if type(left) == type(right) == list:
55          # zip_longest puts "None" when out of items
56          for pair in zip_longest(left, right):
57              comp = compare(*pair)
58              logger.info(comp)
59              if comp is not None:
60                  return comp
61      if type(left) != type(right):
62          if type(left) == int:
63              left = [left]
64          elif type(right) == int:
65              right = [right]
66          return compare(left, right)
67      if type(left) == type(right) == int:
68          if left < right:
69              return True
70          elif left > right:
71              return False
72          else:
73              return None
74  
75  if __name__ == '__main__':
76      if '--one' in sys.argv:
77          indexes = []
78          for index, pair in enumerate(gimme_pairs(), start=1):
79              logger.info(pair)
80              if Packet(pair[0]) < Packet(pair[1]):
81                  indexes.append(index)
82          print('part one answer:', sum(indexes))
83      if '--two' in sys.argv:
84          packets = list(gimme_packets())
85          for _ in EXTRA_PACKETS:
86              packets.append(_)
87          indexes = []
88          for index, packet in enumerate(sorted([Packet(x) for x in packets]), start=1):
89              logger.error(f'{index}, {packet}')
90              if packet.value in EXTRA_PACKETS:
91                  indexes.append(index)
92          print('part two answer:', math.prod(indexes))