Day 16
This commit is contained in:
parent
ece672dff2
commit
f8e5e900a2
2 changed files with 319 additions and 0 deletions
1
input/16.txt
Normal file
1
input/16.txt
Normal file
|
@ -0,0 +1 @@
|
|||
220D69802BE00A0803711E1441B1006E39C318A12730C200DCE66D2CCE360FA0055652CD32966E3004677EDF600B0803B1361741510076254138D8A00E4FFF3E3393ABE4FC7AC10410010799D2A4430003764DBE281802F3102CA00D4840198430EE0E00021D04E3F41F84AE0154DFDE65A17CCBFAFA14ADA56854FE5E3FD5BCC53B0D2598027A00848C63F2B918C7E513DEC3290051B3867E009CCC5FE46BD520007FE5E8AD344B37583D0803E40085475887144C01A8C10FE2B9803B0720D45A3004652FD8FA05F80122CAF91E5F50E66BEF8AB000BB0F4802039C20917B920B9221200ABF0017B9C92CCDC76BD3A8C4012CCB13CB22CDB243E9C3D2002067440400D9BE62DAC4D2DC0249BF76B6F72BE459B279F759AE7BE42E0058801CC059B08018A0070012CEC045BA01006C03A8000D46C02FA000A8EA007200800E00618018E00410034220061801D36BF178C01796FC52B4017100763547E86000084C7E8910AC0027E9B029FE2F4952F96D81B34C8400C24AA8CDAF4F1E98027C00FACDE3BA86982570D13AA640195CD67B046F004662711E989C468C01F1007A10C4C8320008742287117C401A8C715A3FC2C8EB3777540048272DFE7DE1C0149AC8BC9E79D63200B674013978E8BE5E3A2E9AA3CCDD538C01193CFAB0A146006AA00087C3E88B130401D8E304A239802F39FAC922C0169EA3248DF2D600247C89BCDFE9CA7FFD8BB49686236C9FF9795D80C0139BEC4D6C017978CF78C5EB981FCE7D4D801FA9FB63B14789534584010B5802F3467346D2C1D1E080355B00424FC99290C7E5D729586504803A2D005E677F868C271AA479CEEB131592EE5450043A932697E6A92C6E164991EFC4268F25A294600B5002A3393B31CC834B972804D2F3A4FD72B928E59219C9C771EC3DC89D1802135C9806802729694A6E723FD6134C0129A019E600
|
318
src/bin/16.rs
Normal file
318
src/bin/16.rs
Normal file
|
@ -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<Packet>),
|
||||
}
|
||||
|
||||
#[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<dyn Iterator<Item = Bit>>);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue