1use std::iter::{from_fn, repeat_with};
16use std::str::Bytes;
17
18use crate::util::parse::*;
19
20struct BitStream<'a> {
21 available: u64,
22 bits: u64,
23 read: u64,
24 iter: Bytes<'a>,
25}
26
27impl BitStream<'_> {
28 fn from(s: &str) -> BitStream<'_> {
29 BitStream { available: 0, bits: 0, read: 0, iter: s.bytes() }
30 }
31
32 fn next(&mut self, amount: u64) -> u64 {
33 while self.available < amount {
34 self.available += 4;
35 self.bits = (self.bits << 4) | self.hex_to_binary();
36 }
37
38 self.available -= amount;
39 self.read += amount;
40
41 let mask = (1 << amount) - 1;
42 (self.bits >> self.available) & mask
43 }
44
45 fn hex_to_binary(&mut self) -> u64 {
46 let b = self.iter.next().unwrap();
47 if b.is_ascii_digit() { b.to_decimal() } else { u64::from(b - b'A' + 10) }
48 }
49}
50
51pub enum Packet {
52 Literal { version: u64, value: u64 },
53 Operator { version: u64, type_id: u64, packets: Vec<Self> },
54}
55
56impl Packet {
57 fn from(bit_stream: &mut BitStream<'_>) -> Self {
58 let version = bit_stream.next(3);
59 let type_id = bit_stream.next(3);
60
61 if type_id == 4 {
62 let mut todo = true;
63 let mut value = 0;
64
65 while todo {
66 todo = bit_stream.next(1) == 1;
67 value = (value << 4) | bit_stream.next(4);
68 }
69
70 Self::Literal { version, value }
71 } else {
72 let packets = if bit_stream.next(1) == 0 {
73 let target = bit_stream.next(15) + bit_stream.read;
74 from_fn(|| (bit_stream.read < target).then(|| Self::from(bit_stream))).collect()
75 } else {
76 let sub_packets = bit_stream.next(11) as usize;
77 repeat_with(|| Self::from(bit_stream)).take(sub_packets).collect()
78 };
79
80 Self::Operator { version, type_id, packets }
81 }
82 }
83}
84
85pub fn parse(input: &str) -> Packet {
86 Packet::from(&mut BitStream::from(input))
87}
88
89pub fn part1(packet: &Packet) -> u64 {
90 match packet {
91 Packet::Literal { version, .. } => *version,
92 Packet::Operator { version, packets, .. } => {
93 *version + packets.iter().map(part1).sum::<u64>()
94 }
95 }
96}
97
98pub fn part2(packet: &Packet) -> u64 {
99 match packet {
100 Packet::Literal { value, .. } => *value,
101 Packet::Operator { type_id, packets, .. } => {
102 let mut iter = packets.iter().map(part2);
103 match type_id {
104 0 => iter.sum(),
105 1 => iter.product(),
106 2 => iter.min().unwrap(),
107 3 => iter.max().unwrap(),
108 5 => u64::from(iter.next().unwrap() > iter.next().unwrap()),
109 6 => u64::from(iter.next().unwrap() < iter.next().unwrap()),
110 7 => u64::from(iter.next().unwrap() == iter.next().unwrap()),
111 _ => unreachable!(),
112 }
113 }
114 }
115}