AoC21/src/day16.rs

241 lines
6.4 KiB
Rust

use std::str::Chars;
use itertools::Itertools;
pub fn day16() {
assert_eq!(
parse_hex_str("D2FE28"),
Packet {
version: 6,
type_id: 4,
length: 21,
payload: Payload::Literal(2021),
},
);
assert_eq!(
parse_hex_str("38006F45291200"),
Packet {
version: 1,
type_id: 6,
length: 49,
payload: Payload::Operator(vec![
Packet {
version: 6,
type_id: 4,
length: 11,
payload: Payload::Literal(10),
},
Packet {
version: 2,
type_id: 4,
length: 16,
payload: Payload::Literal(20),
},
]),
},
);
dbg!(parse_hex_str("EE00D40C823060"));
let sums = &[
"8A004A801A8002F478",
"620080001611562C8802118E34",
"C0015000016115A2E0802F182340",
"A0016C880162017C3686B18A3D4780",
]
.map(|s| parse_hex_str(s).sum_versions());
assert_eq!(sums, &[16, 12, 23, 31]);
let input = include_str!("../input/day16.txt");
let packet = parse_hex_str(input);
println!("part 1: {}", packet.sum_versions());
let values = &[
"C200B40A82",
"04005AC33890",
"880086C3E88112",
"CE00C43D881120",
"D8005AC2A8F0",
"F600BC2D8F",
"9C005AC2F8F0",
"9C0141080250320F1802104A08",
]
.map(|s| parse_hex_str(s).eval());
assert_eq!(values, &[3, 54, 7, 9, 1, 0, 0, 1]);
println!("part 2: {}", packet.eval());
}
fn parse_hex_str(hex_str: &str) -> Packet {
let mut bits = HexToBits::new(hex_str.chars());
parse_packet(&mut bits, 0)
}
fn parse_packet<'a>(bits: &mut HexToBits<'a>, depth: u32) -> Packet {
let mut packet_len = 6;
let version = bits.read(3);
let type_id = bits.read(3);
let payload: Payload;
// println!("type id {} at depth {}", type_id, depth);
if type_id == 4 {
let mut val = 0;
loop {
let is_last = !bits.next().unwrap();
val <<= 4;
val |= bits.read(4);
packet_len += 5;
if is_last {
break;
}
}
payload = Payload::Literal(val);
} else {
packet_len += 1;
let length_type = bits.next().unwrap();
let length = if length_type {
packet_len += 11;
bits.read(11)
} else {
packet_len += 15;
bits.read(15)
};
// println!("length type: {}, length: {}", length_type, length);
let mut sub_packets = vec![];
let mut sub_packets_len = 0;
loop {
if length_type && sub_packets.len() >= length {
break;
} else if !length_type && sub_packets_len >= length {
break;
}
let packet = parse_packet(bits, depth + 1);
sub_packets_len += packet.length;
// println!(
// "read packet of length {} at depth {}",
// packet.length,
// depth + 1
// );
sub_packets.push(packet);
}
payload = Payload::Operator(sub_packets);
packet_len += sub_packets_len;
}
Packet {
version,
type_id,
length: packet_len,
payload,
}
}
struct HexToBits<'a> {
hex_chars: Chars<'a>,
current: u32,
current_bits_remaining: u32,
read_so_far: usize,
}
impl<'a> HexToBits<'a> {
fn new(chars: Chars<'a>) -> Self {
Self {
hex_chars: chars,
current: 0,
current_bits_remaining: 0,
read_so_far: 0,
}
}
fn read(&mut self, len: u32) -> usize {
let mut res = 0;
for _ in 0..len {
res <<= 1;
res |= if self.next().unwrap() { 1 } else { 0 };
}
res
}
}
impl<'a> Iterator for HexToBits<'a> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
if self.current_bits_remaining > 0 {
let res = Some((self.current >> self.current_bits_remaining - 1) & 1 == 1);
self.current_bits_remaining -= 1;
self.read_so_far += 1;
res
} else if let Some(c) = self.hex_chars.next() {
self.current = c.to_digit(16).unwrap();
self.current_bits_remaining = 3;
self.read_so_far += 1;
Some((self.current >> 3) & 1 == 1)
} else {
None
}
}
}
#[derive(Debug, PartialEq)]
struct Packet {
version: usize,
type_id: usize,
length: usize,
payload: Payload,
}
impl Packet {
fn sum_versions(&self) -> usize {
match self.payload {
Payload::Literal(_) => self.version,
Payload::Operator(ref sub) => {
self.version + sub.iter().map(|p| p.sum_versions()).sum::<usize>()
}
}
}
fn eval(&self) -> usize {
match self.payload {
Payload::Literal(n) => n,
Payload::Operator(ref sub) => {
let sub_vals = sub.iter().map(|p| p.eval());
match self.type_id {
0 => sub_vals.sum(),
1 => sub_vals.product(),
2 => sub_vals.min().unwrap(),
3 => sub_vals.max().unwrap(),
5 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a > b {
1
} else {
0
}
}
6 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a < b {
1
} else {
0
}
}
7 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a == b {
1
} else {
0
}
}
_ => panic!(),
}
}
}
}
}
#[derive(Debug, PartialEq)]
enum Payload {
Literal(usize),
Operator(Vec<Packet>),
}