From f8e5e900a2ac293e0738f62999fe5ee218a1ee07 Mon Sep 17 00:00:00 2001 From: Lars Martens Date: Thu, 16 Dec 2021 23:58:09 +0100 Subject: [PATCH] Day 16 --- input/16.txt | 1 + src/bin/16.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 input/16.txt create mode 100644 src/bin/16.rs diff --git a/input/16.txt b/input/16.txt new file mode 100644 index 0000000..36cb0f5 --- /dev/null +++ b/input/16.txt @@ -0,0 +1 @@ +220D69802BE00A0803711E1441B1006E39C318A12730C200DCE66D2CCE360FA0055652CD32966E3004677EDF600B0803B1361741510076254138D8A00E4FFF3E3393ABE4FC7AC10410010799D2A4430003764DBE281802F3102CA00D4840198430EE0E00021D04E3F41F84AE0154DFDE65A17CCBFAFA14ADA56854FE5E3FD5BCC53B0D2598027A00848C63F2B918C7E513DEC3290051B3867E009CCC5FE46BD520007FE5E8AD344B37583D0803E40085475887144C01A8C10FE2B9803B0720D45A3004652FD8FA05F80122CAF91E5F50E66BEF8AB000BB0F4802039C20917B920B9221200ABF0017B9C92CCDC76BD3A8C4012CCB13CB22CDB243E9C3D2002067440400D9BE62DAC4D2DC0249BF76B6F72BE459B279F759AE7BE42E0058801CC059B08018A0070012CEC045BA01006C03A8000D46C02FA000A8EA007200800E00618018E00410034220061801D36BF178C01796FC52B4017100763547E86000084C7E8910AC0027E9B029FE2F4952F96D81B34C8400C24AA8CDAF4F1E98027C00FACDE3BA86982570D13AA640195CD67B046F004662711E989C468C01F1007A10C4C8320008742287117C401A8C715A3FC2C8EB3777540048272DFE7DE1C0149AC8BC9E79D63200B674013978E8BE5E3A2E9AA3CCDD538C01193CFAB0A146006AA00087C3E88B130401D8E304A239802F39FAC922C0169EA3248DF2D600247C89BCDFE9CA7FFD8BB49686236C9FF9795D80C0139BEC4D6C017978CF78C5EB981FCE7D4D801FA9FB63B14789534584010B5802F3467346D2C1D1E080355B00424FC99290C7E5D729586504803A2D005E677F868C271AA479CEEB131592EE5450043A932697E6A92C6E164991EFC4268F25A294600B5002A3393B31CC834B972804D2F3A4FD72B928E59219C9C771EC3DC89D1802135C9806802729694A6E723FD6134C0129A019E600 diff --git a/src/bin/16.rs b/src/bin/16.rs new file mode 100644 index 0000000..edf4a67 --- /dev/null +++ b/src/bin/16.rs @@ -0,0 +1,318 @@ +use core::panic; +use std::iter; + +fn main() { + let mut bits = Bits::from(include_str!("../../input/16.txt")); + let (packet, _) = Packet::parse(&mut bits); + println!("First solution: {}", packet.version_sum()); + println!("Second solution: {}", packet.evaluate()); +} + +#[derive(Debug, PartialEq, Eq)] +struct Packet { + version: u64, + payload: Payload, +} + +#[derive(Debug, PartialEq, Eq)] +enum Payload { + Literal(u64), + Operator(Operation, Vec), +} + +#[derive(Debug, PartialEq, Eq)] +enum Operation { + Sum, + Product, + Minimum, + Maximum, + GreaterThan, + LessThan, + EqualTo, +} + +#[derive(Debug, PartialEq, Eq)] +enum Length { + Count(u64), + Bits(u64), +} + +#[derive(Debug, PartialEq, Eq)] +struct Bit(bool); + +struct Bits(Box>); + +impl Bit { + const TRUE: Self = Bit(true); + const FALSE: Self = Bit(false); +} + +impl Bits { + fn from(input: &'static str) -> Self { + Self(Box::new( + input + .chars() + .map(|c| c.to_digit(16).unwrap() as u64) + .flat_map(|d: u64| [3, 2, 1, 0].into_iter().map(move |shift| (d >> shift) & 1)) + .map(|n| n == 1) + .map(Bit), + )) + } + + /// Get the next n bits or die trying + fn take(&mut self, n: usize) -> Bits { + let mut b = Vec::new(); + for _ in 0..n { + b.push(self.0.next().unwrap()); + } + Bits(Box::new(b.into_iter())) + } + + /// Get the next bit or panic + fn next(&mut self) -> Bit { + self.0.next().unwrap() + } + + /// merge self with other. + fn merge(self, other: Self) -> Self { + Bits(Box::new(self.0.chain(other.0))) + } + + /// Interpret all the bits as a number. + fn num(self) -> u64 { + let mut buf = 0; + for next in self.0 { + buf = (buf << 1) | (next.0 as u64) + } + buf + } +} + +impl Default for Bits { + fn default() -> Self { + Self(Box::new(iter::empty())) + } +} + +impl Packet { + /// All parse methods everywhere return the parsed thing and the + /// number of bits consumed. + fn parse(bits: &mut Bits) -> (Self, u64) { + let version = bits.take(3).num(); + let (payload, n) = Payload::parse(bits); + (Self { version, payload }, n + 3) + } + + fn version_sum(&self) -> u64 { + let mut sum = self.version; + if let Payload::Operator(_, packets) = &self.payload { + for p in packets { + sum += p.version_sum(); + } + } + sum + } + + fn evaluate(&self) -> u64 { + match &self.payload { + Payload::Literal(n) => *n, + Payload::Operator(Operation::Sum, ps) => ps.iter().map(|p| p.evaluate()).sum(), + Payload::Operator(Operation::Product, ps) => ps.iter().map(|p| p.evaluate()).product(), + Payload::Operator(Operation::Minimum, ps) => { + ps.iter().map(|p| p.evaluate()).min().unwrap() + } + Payload::Operator(Operation::Maximum, ps) => { + ps.iter().map(|p| p.evaluate()).max().unwrap() + } + Payload::Operator(Operation::GreaterThan, ps) => { + if ps[0].evaluate() > ps[1].evaluate() { + 1 + } else { + 0 + } + } + Payload::Operator(Operation::LessThan, ps) => { + if ps[0].evaluate() < ps[1].evaluate() { + 1 + } else { + 0 + } + } + Payload::Operator(Operation::EqualTo, ps) => { + if ps[0].evaluate() == ps[1].evaluate() { + 1 + } else { + 0 + } + } + } + } +} + +impl Payload { + fn parse(bits: &mut Bits) -> (Self, u64) { + let op = match bits.take(3).num() { + 0 => Some(Operation::Sum), + 1 => Some(Operation::Product), + 2 => Some(Operation::Minimum), + 3 => Some(Operation::Maximum), + 4 => None, + 5 => Some(Operation::GreaterThan), + 6 => Some(Operation::LessThan), + 7 => Some(Operation::EqualTo), + n => panic!("unknown operation: {}", n), + }; + let (p, n) = match op { + None => Self::parse_literal(bits), + Some(op) => Self::parse_operator(op, bits), + }; + (p, n + 3) + } + + fn parse_operator(op: Operation, bits: &mut Bits) -> (Self, u64) { + let mut counter = 0; + let (required, b) = Length::parse(bits); + counter += b; + + let mut result = Vec::new(); + let mut child_bit_counter = 0; + + loop { + // Check if we parsed enough things + if match required { + Length::Count(c) => result.len() as u64 >= c, + Length::Bits(b) => child_bit_counter >= b, + } { + break; + } + + // Parse child + let (child, b) = Packet::parse(bits); + child_bit_counter += b; + result.push(child); + } + + counter += child_bit_counter; + (Self::Operator(op, result), counter) + } + + fn parse_literal(bits: &mut Bits) -> (Self, u64) { + let mut more = Bit::TRUE; + let mut result = Bits::default(); + let mut counter = 0; + while more == Bit::TRUE { + let mut chunk = bits.take(5); + counter += 5; + more = chunk.next(); + result = result.merge(chunk); + } + (Self::Literal(result.num()), counter) + } +} + +impl Length { + fn parse(bits: &mut Bits) -> (Self, u64) { + match bits.next() { + Bit::FALSE => (Length::Bits(bits.take(15).num()), 16), + Bit::TRUE => (Length::Count(bits.take(11).num()), 12), + } + } +} + +#[cfg(test)] +mod test { + use crate::{Bits, Operation, Packet, Payload}; + + #[test] + fn nums() { + assert_eq!(Bits::from("F").take(4).num(), 15); + assert_eq!(Bits::from("F").take(2).num(), 3); + assert_eq!(Bits::from("A").take(4).num(), 10); + assert_eq!(Bits::from("A").take(2).num(), 2); + assert_eq!(Bits::from("ABC").take(12).num(), 0xABC); + } + + #[test] + fn example_literal() { + let mut bits = Bits::from("D2FE28"); + let (actual, _) = Packet::parse(&mut bits); + let expected = Packet { + version: 6, + payload: Payload::Literal(2021), + }; + assert_eq!(expected, actual); + } + + #[test] + fn example_operator() { + let mut bits = Bits::from("38006F45291200"); + let (actual, _) = Packet::parse(&mut bits); + let expected = Packet { + version: 1, + payload: Payload::Operator( + Operation::LessThan, + vec![ + Packet { + version: 6, + payload: Payload::Literal(10), + }, + Packet { + version: 2, + payload: Payload::Literal(20), + }, + ], + ), + }; + assert_eq!(expected, actual); + } + + #[test] + fn example_sums() { + let mut bits = Bits::from("8A004A801A8002F478"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 16); + + let mut bits = Bits::from("620080001611562C8802118E34"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 12); + + let mut bits = Bits::from("C0015000016115A2E0802F182340"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 23); + + let mut bits = Bits::from("A0016C880162017C3686B18A3D4780"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 31); + } + + #[test] + fn example_evaluations() { + let mut bits = Bits::from("C200B40A82"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 3); + + let mut bits = Bits::from("04005AC33890"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 54); + + let mut bits = Bits::from("880086C3E88112"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 7); + + let mut bits = Bits::from("D8005AC2A8F0"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 1); + + let mut bits = Bits::from("F600BC2D8F"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 0); + + let mut bits = Bits::from("9C005AC2F8F0"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 0); + + let mut bits = Bits::from("9C0141080250320F1802104A08"); + let (packet, _) = Packet::parse(&mut bits); + assert_eq!(packet.version_sum(), 1); + } +}