Skip to content

Commit

Permalink
finish day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
mflinn-broad committed Dec 19, 2021
1 parent 5ae5a93 commit 6a51ed2
Showing 1 changed file with 63 additions and 100 deletions.
163 changes: 63 additions & 100 deletions src/days/day16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8> {
Expand Down Expand Up @@ -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)),
}
}

Expand All @@ -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::<u64>();

(bytes, sub_packet_versions)
let mut sub_packet_values: Vec<u64> = 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)
}
}

0 comments on commit 6a51ed2

Please sign in to comment.