1
+ import pprint
2
+
3
+ import sys
4
+ sys .path .append ('..' )
5
+
6
+ import lib .text
7
+
1
8
class BITSPacketDecoder (object ):
2
9
def __init__ (self , packet ):
3
10
self .packet = packet
4
11
self .bits = self .hex2bin (self .packet )
12
+ self .bit_labels = ''
5
13
self .index = 0
6
14
7
15
def hex2bin (self , hex_string ):
@@ -15,24 +23,29 @@ def bits_left(self):
15
23
ret = len (self .bits ) - self .index
16
24
return ret
17
25
18
- def read (self , read_len ):
26
+ def read (self , read_len , bit_label ):
19
27
if self .bits_left () < read_len :
20
28
print ("read underrun" )
21
29
return None
22
30
23
31
ret = self .bits [self .index :self .index + read_len ]
24
32
25
- #print(self.bits)
26
- #print(' ' * self.index + '*' * read_len + ' = ' + ret + ' (' + str(int(ret, 2)) + ')')
27
- #print()
33
+ preview_width = 60
34
+ skip = max (self .index - preview_width , 0 )
35
+
36
+ print (self .bits [skip :skip + preview_width * 2 ])
37
+ print (self .bit_labels [skip :] + lib .text .bcolor ('green' , bit_label * read_len ) + " -> %s (dec %s)" % (ret , str (int (ret , 2 ))))
38
+ print ()
39
+
40
+ self .bit_labels += bit_label * read_len
28
41
29
42
self .index += read_len
30
43
31
44
return ret
32
45
33
46
def read_packet (self ):
34
- version = int (self .read (3 ), 2 )
35
- type_id = int (self .read (3 ), 2 )
47
+ version = int (self .read (3 , 'V' ), 2 )
48
+ type_id = int (self .read (3 , 'T' ), 2 )
36
49
37
50
print ('version: %s type_id: %s' % (version , type_id ))
38
51
@@ -47,28 +60,38 @@ def parse_payload_4(self, version, type_id):
47
60
bit_string = ""
48
61
more = 1
49
62
while more :
50
- more = int (self .read (1 ))
51
- bit_string += self .read (4 )
63
+ more = int (self .read (1 , 'n' ))
64
+ bit_string += self .read (4 , 'N' )
52
65
53
66
return {'version' : version , 'type_id' : type_id , 'literal' : int (bit_string , 2 )}
54
67
55
68
def parse_payload_op (self , version , type_id ):
56
69
subpackets = []
57
70
58
- length_type_id = int (self .read (1 ))
71
+ length_type_id = int (self .read (1 , 'I' ))
72
+
73
+ subpacket_length = None
74
+ subpacket_count = None
59
75
60
76
if length_type_id == 0 :
61
- subpacket_length = int (self .read (15 ), 2 )
77
+ subpacket_length = int (self .read (15 , 'L' ), 2 )
78
+ bit_stop = self .index + subpacket_length
62
79
elif length_type_id == 1 :
63
- subpacket_count = int (self .read (11 ), 2 )
80
+ subpacket_count = int (self .read (11 , 'C' ), 2 )
81
+
82
+ packet_count = 0
83
+ while (
84
+ (subpacket_count and packet_count < subpacket_count )
85
+ or
86
+ (subpacket_length and self .index < bit_stop )
87
+ ) and self .bits_left () >= 11 :
64
88
65
- while self .bits_left () > 12 :
66
89
subpacket = self .read_packet ()
90
+ packet_count += 1
67
91
if subpacket :
68
92
subpackets .append (subpacket )
69
93
else :
70
- print ("no subpacket?, breaking" )
71
- break
94
+ raise ValueError ('no subpacket when expecting subpacket' )
72
95
73
96
return {'version' : version , 'type_id' : type_id , 'subpackets' : subpackets }
74
97
@@ -89,15 +112,79 @@ def get_version_sum(self, packet):
89
112
90
113
return version_sum
91
114
92
- def parse_packets (self , data ):
93
- print (data )
94
- bd = BITSPacketDecoder (data )
95
- print (bd .bits )
96
- print ()
115
+ def evaluate_packet (self , packet , depth = 0 ):
116
+ type_id = packet ['type_id' ]
117
+
118
+ if type_id == 4 and 'subpackets' in packet :
119
+ raise ValueError ('WTF' )
120
+
121
+ if type_id == 4 :
122
+ return packet ['literal' ]
123
+
124
+ if 'subpackets' in packet :
125
+ values = []
126
+ for subpacket in packet ['subpackets' ]:
127
+ values .append (self .evaluate_packet (subpacket , depth + 1 ))
128
+
129
+ print ((' ' * depth ) + str (depth ) + ' eval %s of %s' % (type_id , values ))
130
+
131
+ if type_id == 0 :
132
+ ret = sum (values )
133
+ print ("sum %s = %s" % (values , ret ))
134
+ return ret
135
+ elif type_id == 1 :
136
+ product = 1
137
+ for v in values :
138
+ product *= v
139
+ print ("product %s = %s" % (values , product ))
140
+ return product
141
+ elif type_id == 2 :
142
+ ret = min (values )
143
+ print ("min %s = %s" % (values , ret ))
144
+ return ret
145
+ elif type_id == 3 :
146
+ ret = max (values )
147
+ print ("max %s = %s" % (values , ret ))
148
+ return ret
149
+ elif type_id == 4 :
150
+ raise ValueError ("WTF srsly" )
151
+ elif type_id == 5 :
152
+ ret = 1 if values [0 ] > values [1 ] else 0
153
+ print ("%s gt %s = %s" % (values [0 ], values [1 ], ret ))
154
+ return ret
155
+ elif type_id == 6 :
156
+ ret = 1 if values [0 ] < values [1 ] else 0
157
+ print ("%s lt %s = %s" % (values [0 ], values [1 ], ret ))
158
+ return ret
159
+ elif type_id == 7 :
160
+ ret = 1 if values [0 ] == values [1 ] else 0
161
+ print ("%s eq %s = %s" % (values [0 ], values [1 ], ret ))
162
+ return ret
163
+ else :
164
+ raise ValueError ('Unknown type_id %s' % type_id )
165
+
166
+ print ('mystery packet' )
167
+ pprint .pprint (packet )
168
+ raise ValueError ('WTF' )
97
169
98
- packets = bd .read_packet ()
170
+ def parse_packets (self , transmissions ):
171
+ ret = {}
172
+ for transmission in transmissions :
173
+ print (transmission )
99
174
100
- return packets
175
+ bd = BITSPacketDecoder (transmission )
176
+
177
+ parsed_transmission = bd .read_packet ()
178
+ print (parsed_transmission )
179
+
180
+ if bd .bits_left ():
181
+ leftovers = bd .read (bd .bits_left (), 'x' )
182
+ if int (leftovers ):
183
+ raise ValueError ("Left bits on the table: %s" % leftovers )
184
+
185
+ ret .update ({transmission : parsed_transmission })
186
+
187
+ return ret
101
188
102
189
def get_data ():
103
190
return [l .rstrip () for l in open ('data.txt' , 'r' ).readlines ()]
@@ -108,20 +195,24 @@ def get_test_data():
108
195
def solution_part_1 (data ):
109
196
bits = BITS ()
110
197
bits .load_data (data )
111
- packets = bits .parse_packets (data )
112
- version_sum = bits .get_version_sum (packets )
113
- print ('version_sum' , version_sum )
198
+ parsed_transmissions = bits .parse_packets (data )
199
+
200
+ for transmission , parsed_transmission in parsed_transmissions .items ():
201
+ version_sum = bits .get_version_sum (parsed_transmission )
202
+ print ('version_sum' , version_sum )
114
203
115
204
def solution_part_2 (data ):
116
205
bits = BITS ()
117
206
bits .load_data (data )
118
- packets = bits .parse_packets (data )
119
- result = bits .evaluate_packets (packets )
120
- print ('eval results' , result )
207
+ parsed_transmissions = bits .parse_packets (data )
208
+ for transmission , parsed_transmission in parsed_transmissions .items ():
209
+ print (transmission )
210
+ result = bits .evaluate_packet (parsed_transmission )
211
+ print ('eval results' , result )
121
212
122
213
if __name__ == '__main__' :
123
- solution_part_1 (get_test_data ())
124
- solution_part_1 (get_data ())
214
+ # solution_part_1(get_test_data())
215
+ # solution_part_1(get_data())
125
216
126
217
#solution_part_2(get_test_data())
127
- # solution_part_2(get_data())
218
+ solution_part_2 (get_data ())
0 commit comments