···11+import fileinput
22+from utils import mul
33+44+55+HEX_MAPPING = {
66+ '0': '0000',
77+ '1': '0001',
88+ '2': '0010',
99+ '3': '0011',
1010+ '4': '0100',
1111+ '5': '0101',
1212+ '6': '0110',
1313+ '7': '0111',
1414+ '8': '1000',
1515+ '9': '1001',
1616+ 'A': '1010',
1717+ 'B': '1011',
1818+ 'C': '1100',
1919+ 'D': '1101',
2020+ 'E': '1110',
2121+ 'F': '1111',
2222+}
2323+2424+OPERATORS = {
2525+ 0: '+',
2626+ 1: '*',
2727+ 2: 'min',
2828+ 3: 'max',
2929+ 5: '>',
3030+ 6: '<',
3131+ 7: '=='
3232+}
3333+3434+3535+def parse_packets(bits, num_subpackets=None, bit_length=None, depth=0, quiet=False):
3636+ """
3737+ Given a bitstring `bits`, parses `num_subpackets` subpackets, and returns ([packets], bit_length, version).
3838+3939+ If the argument `num_subpackets` is given, this dictates the number of packets
4040+ to parse from `bits` before returning.
4141+4242+ If the argument `bit_length` is given, this dictates how many bits to process
4343+ before returning however many packets the parser got through.
4444+4545+ If `quiet` is False, the parser will print the operator and values processed,
4646+ with various nesting levels based on `depth` (incremented per recursive call).
4747+ """
4848+4949+ i = 0 # current pointer into `bits`
5050+ subs = [] # list of subpackets currently parsed
5151+ version = 0 # the version so far (?)
5252+5353+ try:
5454+ while True:
5555+ # Standard Packet Header
5656+5757+ # Read 3-bit version
5858+ version += int(bits[i:i+3], 2)
5959+ i += 3
6060+6161+ # Read 3-bit type ID
6262+ ttype = int(bits[i:i+3], 2)
6363+ i += 3
6464+6565+ # Packets with type ID 4 represent a literal value.
6666+ if ttype == 4:
6767+ lit = ''
6868+6969+ # Read groups of 5 bits until the final group
7070+ # (prefixed 0) is seen. Then stop reading.
7171+ while True:
7272+ group = bits[i:i+5]
7373+ i += 5
7474+ lit += group[1:]
7575+ if group[0] == '0':
7676+ break
7777+7878+ try:
7979+ lit = int(lit, 2)
8080+ subs.append(lit)
8181+ except Exception:
8282+ print "bad literal, moving on"
8383+8484+ # Otherwise, process an operator.
8585+ else:
8686+ # Operator packet mode is based on its 1-bit length type ID.
8787+ len_type_id = bits[i]
8888+ i += 1
8989+9090+ # Specifies the bit length of contained subpackets.
9191+ if len_type_id == '0':
9292+ sub_len = int(bits[i:i+15], 2)
9393+ i += 15
9494+ subpackets, new_i, new_version = parse_packets(bits[i:i+sub_len], bit_length=sub_len, depth=depth + 1, quiet=quiet)
9595+9696+ i += new_i
9797+ version += new_version
9898+9999+ # Specifies total number of subpackets.
100100+ elif len_type_id == '1':
101101+ sub_packets = int(bits[i:i+11], 2)
102102+ i += 11
103103+ subpackets, new_i, new_version = parse_packets(bits[i:], num_subpackets=sub_packets, depth=depth+1, quiet=quiet)
104104+105105+ i += new_i
106106+ version += new_version
107107+ else:
108108+ print "Unknown length type ID"
109109+110110+ # Process operators
111111+ if not quiet:
112112+ print " " * depth, OPERATORS[ttype], subpackets
113113+114114+ if ttype == 0:
115115+ subs.append(sum(subpackets))
116116+ elif ttype == 1:
117117+ subs.append(mul(subpackets))
118118+ elif ttype == 2:
119119+ subs.append(min(subpackets))
120120+ elif ttype == 3:
121121+ subs.append(max(subpackets))
122122+ elif ttype == 5:
123123+ subs.append(1 if subpackets[0] > subpackets[1] else 0)
124124+ elif ttype == 6:
125125+ subs.append(1 if subpackets[0] < subpackets[1] else 0)
126126+ elif ttype == 7:
127127+ subs.append(1 if subpackets[0] == subpackets[1] else 0)
128128+129129+ # Check exit conditions for loop.
130130+ if num_subpackets is not None and len(subs) == num_subpackets:
131131+ # IMPORTANT: return i and not len(i); it is not an invariant
132132+ # that we read the full `bits`, since there may have been
133133+ # some trailing data that we ignore since it falls out of
134134+ # the range of `num_subpackets` subpackets.
135135+ return subs, i, version
136136+ elif bit_length is not None and i > bit_length:
137137+ return subs, len(bits), version
138138+ elif i >= len(bits):
139139+ return subs, len(bits), version
140140+141141+ except Exception as e:
142142+ print "Unexpected parsing error:", e
143143+ return subs, i, version
144144+145145+146146+# Read problem input.
147147+BITS = ''.join(HEX_MAPPING[byte] for byte in fileinput.input()[0].strip())
148148+149149+# Problem guarantees the input consists of precisely 1 outer packet.
150150+packets, _, total_version = parse_packets(BITS, num_subpackets=1, quiet=True)
151151+152152+print "Part 1:", total_version
153153+print "Part 2:", packets[0]