1
0
Fork 0
This commit is contained in:
Lars Martens 2021-12-16 23:58:09 +01:00
parent ece672dff2
commit f8e5e900a2
2 changed files with 319 additions and 0 deletions

1
input/16.txt Normal file
View file

@ -0,0 +1 @@
220D69802BE00A0803711E1441B1006E39C318A12730C200DCE66D2CCE360FA0055652CD32966E3004677EDF600B0803B1361741510076254138D8A00E4FFF3E3393ABE4FC7AC10410010799D2A4430003764DBE281802F3102CA00D4840198430EE0E00021D04E3F41F84AE0154DFDE65A17CCBFAFA14ADA56854FE5E3FD5BCC53B0D2598027A00848C63F2B918C7E513DEC3290051B3867E009CCC5FE46BD520007FE5E8AD344B37583D0803E40085475887144C01A8C10FE2B9803B0720D45A3004652FD8FA05F80122CAF91E5F50E66BEF8AB000BB0F4802039C20917B920B9221200ABF0017B9C92CCDC76BD3A8C4012CCB13CB22CDB243E9C3D2002067440400D9BE62DAC4D2DC0249BF76B6F72BE459B279F759AE7BE42E0058801CC059B08018A0070012CEC045BA01006C03A8000D46C02FA000A8EA007200800E00618018E00410034220061801D36BF178C01796FC52B4017100763547E86000084C7E8910AC0027E9B029FE2F4952F96D81B34C8400C24AA8CDAF4F1E98027C00FACDE3BA86982570D13AA640195CD67B046F004662711E989C468C01F1007A10C4C8320008742287117C401A8C715A3FC2C8EB3777540048272DFE7DE1C0149AC8BC9E79D63200B674013978E8BE5E3A2E9AA3CCDD538C01193CFAB0A146006AA00087C3E88B130401D8E304A239802F39FAC922C0169EA3248DF2D600247C89BCDFE9CA7FFD8BB49686236C9FF9795D80C0139BEC4D6C017978CF78C5EB981FCE7D4D801FA9FB63B14789534584010B5802F3467346D2C1D1E080355B00424FC99290C7E5D729586504803A2D005E677F868C271AA479CEEB131592EE5450043A932697E6A92C6E164991EFC4268F25A294600B5002A3393B31CC834B972804D2F3A4FD72B928E59219C9C771EC3DC89D1802135C9806802729694A6E723FD6134C0129A019E600

318
src/bin/16.rs Normal file
View 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);
}
}