From 6a51ed253a4bc19f2a60018c7f5301ccee1d1eaa Mon Sep 17 00:00:00 2001 From: mflinn-broad Date: Sun, 19 Dec 2021 08:08:42 -0500 Subject: [PATCH] finish day 16 --- src/days/day16.rs | 163 ++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 100 deletions(-) diff --git a/src/days/day16.rs b/src/days/day16.rs index 91a2cc1..6731f74 100644 --- a/src/days/day16.rs +++ b/src/days/day16.rs @@ -4,7 +4,7 @@ pub fn run() { let raw_input = util::read_input("inputs/day16.txt").unwrap(); let input = process(&raw_input); - println!("Part 1: {:?}", part_1(&input)); + println!("Result: {:?}", parse(&input)); } fn process(input: &str) -> Vec { @@ -32,7 +32,7 @@ fn parse_type(byte: &[u8]) -> (&[u8], Type) { match type_id { 4 => (&byte[3..], Type::Literal), - _ => (&byte[3..], Type::Operator), + t => (&byte[3..], Type::Operator(t)), } } @@ -42,141 +42,104 @@ fn parse_header(bytes: &[u8]) -> (&[u8], u8, Type) { (remaining, vers, type_id) } -fn parse_literal(mut bytes: &[u8]) -> &[u8] { +fn parse_literal(mut bytes: &[u8]) -> (&[u8], u64) { + let mut literal_bits = vec![]; (0..) .take_while(|_| { let continues = bytes[0] == 1; + literal_bits.extend(&bytes[1..5]); bytes = &bytes[5..]; continues }) .count(); - bytes + (bytes, bits_to_num(&literal_bits)) } -fn parse_operator(mut bytes: &[u8]) -> (&[u8], u64) { +fn parse_operator(mut bytes: &[u8], operator_type: u8) -> (&[u8], u64) { let length_type = bytes[0]; bytes = &bytes[1..]; - match length_type { - 0 => { - let l = bytes - .iter() - .take(15) - .fold(0, |l, &bit| ((l as usize) << 1) ^ bit as usize); - bytes = &bytes[15..]; - let rest = &bytes[l..]; - let mut sub_packets = &bytes[0..l]; - let mut sub_packet_version_count = 0; - while !sub_packets.is_empty() { - let (new_sub_packets, vers) = parse_packet(sub_packets); - sub_packet_version_count += vers; - sub_packets = new_sub_packets; - } - (rest, sub_packet_version_count) - } - 1 => { - let desired_sub_packet_count = bytes - .iter() - .take(11) - .fold(0, |l, &bit| ((l as u32) << 1) ^ bit as u32); - bytes = &bytes[11..]; - let sub_packet_versions = (0..desired_sub_packet_count) - .map(|_| { - let (rem, vers) = parse_packet(bytes); - bytes = rem; - vers - }) - .sum::(); - - (bytes, sub_packet_versions) + let mut sub_packet_values: Vec = vec![]; + + if length_type == 0 { + let l = bits_to_num(&bytes[0..15]) as usize; + bytes = &bytes[15..]; + let rest = &bytes[l..]; + + let mut sub_packets = &bytes[0..l]; + while !sub_packets.is_empty() { + let (new_sub_packets, val) = parse_packet(sub_packets); + sub_packet_values.push(val); + sub_packets = new_sub_packets; } + bytes = rest; + } else { + let desired_sub_packet_count = bits_to_num(&bytes[0..11]); + bytes = &bytes[11..]; + (0..desired_sub_packet_count).for_each(|_| { + let (rem, val) = parse_packet(bytes); + sub_packet_values.push(val); + bytes = rem; + }); + } + + match operator_type { + 0 => (bytes, sub_packet_values.iter().sum()), + 1 => (bytes, sub_packet_values.iter().product()), + 2 => (bytes, *sub_packet_values.iter().min().unwrap()), + 3 => (bytes, *sub_packet_values.iter().max().unwrap()), + 5 => (bytes, (sub_packet_values[0] > sub_packet_values[1]) as u64), + 6 => (bytes, (sub_packet_values[0] < sub_packet_values[1]) as u64), + 7 => (bytes, (sub_packet_values[0] == sub_packet_values[1]) as u64), _ => panic!("unreachable"), } } fn parse_packet(bytes: &[u8]) -> (&[u8], u64) { - let (rest, curr_vers, packet_type) = parse_header(bytes); + let (rest, _, packet_type) = parse_header(bytes); + match packet_type { - Type::Literal => (parse_literal(rest), curr_vers as u64), - Type::Operator => { - let (rest, sub_packet_versions) = parse_operator(rest); - (rest, curr_vers as u64 + sub_packet_versions) - } + Type::Literal => parse_literal(rest), + Type::Operator(t) => parse_operator(rest, t), } } -fn part_1(mut input: &[u8]) -> u64 { - let mut vers_sum = 0; - while input.len() > 6 { - let res = parse_packet(input); - input = res.0; - vers_sum += res.1; - } +fn bits_to_num(bits: &[u8]) -> u64 { + bits.iter().fold(0, |res, &bit| (res << 1) ^ bit as u64) +} - vers_sum +fn parse(input: &[u8]) -> u64 { + parse_packet(input).1 } #[derive(Debug, PartialEq, Eq)] enum Type { Literal, - Operator, + Operator(u8), } #[cfg(test)] mod tests { use super::*; - - #[test] - fn test_parse_ver() { - let (rem, vers) = parse_vers(&[1, 1, 0]); - assert_eq!(vers, 6); - assert!(rem.is_empty()); - - let (rem, vers) = parse_vers(&[1, 0, 1, 1, 0]); - assert_eq!(vers, 5); - assert_eq!(rem, &[1, 0]); - } - - #[test] - fn test_parse_type() { - let (rem, t) = parse_type(&[1, 0, 0]); - assert_eq!(t, Type::Literal); - assert!(rem.is_empty()); - - let (rem, t) = parse_type(&[1, 0, 1, 0, 1, 0]); - assert_eq!(t, Type::Operator); - assert_eq!(rem, &[0, 1, 0]); - } - - #[test] - fn test_parse_header() { - let (rem, vers, t) = parse_header(&[1, 1, 0, 1, 0, 0]); - assert_eq!(vers, 6); - assert_eq!(t, Type::Literal); - assert!(rem.is_empty()); - - let (rem, vers, t) = parse_header(&[1, 0, 1, 0, 0, 1, 1, 0, 0, 1]); - assert_eq!(vers, 5); - assert_eq!(t, Type::Operator); - assert_eq!(rem, &[1, 0, 0, 1]); - } - - #[test] - fn test_parse_literal() { - let rem = parse_literal(&[1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1]); - assert!(rem.is_empty()); - - let rem = parse_literal(&[1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1]); - assert_eq!(rem, &[1, 0, 1]); + extern crate test; + use test::Bencher; + + #[bench] + fn bench_computation(b: &mut Bencher) { + let raw_input = util::read_input("inputs/day16.txt").unwrap(); + b.iter(|| { + let input = process(&raw_input); + parse(&input); + }) + } #[test] - fn test_part_1() { - let input = "8A004A801A8002F478"; + fn test_part_2() { + let input = "C200B40A82"; let input = process(input); - let res = part_1(&input); - assert_eq!(res, 16); - + let result = parse(&input); + assert_eq!(result, 3) } }