2021: day16: part 2

This commit is contained in:
Antoine Martin 2021-12-16 17:53:06 +01:00
parent 78f059b65c
commit c42041017d

View file

@ -1,7 +1,7 @@
use std::fmt::Write;
use std::ops::Range;
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use bitvec::prelude::*;
const INPUT: &str = include_str!("../input/day16.txt");
@ -10,6 +10,7 @@ pub fn run() -> Result<String> {
let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res)
}
@ -20,6 +21,12 @@ fn part1(input: &str) -> Result<u64> {
Ok(packet.version_sum())
}
fn part2(input: &str) -> Result<u64> {
let packet: Packet = input.parse()?;
Ok(packet.value())
}
#[derive(PartialEq, Eq, Debug)]
enum PacketType {
Litteral(LitteralPacket),
@ -44,6 +51,48 @@ impl Packet {
}
}
}
fn value(&self) -> u64 {
match &self.packet {
PacketType::Litteral(lit) => lit.value,
PacketType::Operator(op) => match op.op_type {
OperatorType::Sum => op.sub_packets.iter().map(Packet::value).sum(),
OperatorType::Product => op.sub_packets.iter().map(Packet::value).product(),
OperatorType::Minimum => op.sub_packets.iter().map(Packet::value).min().unwrap(),
OperatorType::Maximum => op.sub_packets.iter().map(Packet::value).max().unwrap(),
OperatorType::GreaterThan => {
debug_assert_eq!(op.sub_packets.len(), 2);
let pack1 = &op.sub_packets[0];
let pack2 = &op.sub_packets[1];
if pack1.value() > pack2.value() {
1
} else {
0
}
}
OperatorType::LessThan => {
debug_assert_eq!(op.sub_packets.len(), 2);
let pack1 = &op.sub_packets[0];
let pack2 = &op.sub_packets[1];
if pack1.value() < pack2.value() {
1
} else {
0
}
}
OperatorType::EqualTo => {
debug_assert_eq!(op.sub_packets.len(), 2);
let pack1 = &op.sub_packets[0];
let pack2 = &op.sub_packets[1];
if pack1.value() == pack2.value() {
1
} else {
0
}
}
},
}
}
}
#[derive(PartialEq, Eq, Debug)]
@ -51,9 +100,21 @@ struct LitteralPacket {
value: u64,
}
#[derive(PartialEq, Eq, Debug)]
enum OperatorType {
Sum,
Product,
Minimum,
Maximum,
GreaterThan,
LessThan,
EqualTo,
}
#[derive(PartialEq, Eq, Debug)]
struct OperatorPacket {
sub_packets: Vec<Packet>,
op_type: OperatorType,
}
impl std::str::FromStr for Packet {
@ -148,11 +209,26 @@ where
SUBPACKET_START_INDEX_TLID0 + length
};
let op_type = match type_id {
0 => OperatorType::Sum,
1 => OperatorType::Product,
2 => OperatorType::Minimum,
3 => OperatorType::Maximum,
4 => unreachable!("impossible, would parse as a litteral packet"),
5 => OperatorType::GreaterThan,
6 => OperatorType::LessThan,
7 => OperatorType::EqualTo,
_ => bail!("unknown type id: {}", type_id),
};
Ok(Packet {
version,
type_id,
bits_used: len,
packet: PacketType::Operator(OperatorPacket { sub_packets }),
packet: PacketType::Operator(OperatorPacket {
sub_packets,
op_type,
}),
})
}
}
@ -163,19 +239,19 @@ where
mod tests {
use super::*;
const PROVIDED1: &str = "D2FE28";
const PROVIDED2: &str = "38006F45291200";
const PROVIDED3: &str = "EE00D40C823060";
const PART1_PROVIDED1: &str = "D2FE28";
const PART1_PROVIDED2: &str = "38006F45291200";
const PART1_PROVIDED3: &str = "EE00D40C823060";
const PROVIDED4: &str = "8A004A801A8002F478";
const PROVIDED5: &str = "620080001611562C8802118E34";
const PROVIDED6: &str = "C0015000016115A2E0802F182340";
const PROVIDED7: &str = "A0016C880162017C3686B18A3D4780";
const PART1_PROVIDED4: &str = "8A004A801A8002F478";
const PART1_PROVIDED5: &str = "620080001611562C8802118E34";
const PART1_PROVIDED6: &str = "C0015000016115A2E0802F182340";
const PART1_PROVIDED7: &str = "A0016C880162017C3686B18A3D4780";
#[test]
fn part1_provided() {
assert_eq!(
PROVIDED1.parse::<Packet>().unwrap(),
PART1_PROVIDED1.parse::<Packet>().unwrap(),
Packet {
version: 6,
type_id: 4,
@ -185,7 +261,7 @@ mod tests {
);
assert_eq!(
PROVIDED2.parse::<Packet>().unwrap(),
PART1_PROVIDED2.parse::<Packet>().unwrap(),
Packet {
version: 1,
type_id: 6,
@ -205,12 +281,13 @@ mod tests {
packet: PacketType::Litteral(LitteralPacket { value: 20 })
},
],
op_type: OperatorType::LessThan,
}),
}
);
assert_eq!(
PROVIDED3.parse::<Packet>().unwrap(),
PART1_PROVIDED3.parse::<Packet>().unwrap(),
Packet {
version: 7,
type_id: 3,
@ -236,18 +313,45 @@ mod tests {
packet: PacketType::Litteral(LitteralPacket { value: 3 })
},
],
op_type: OperatorType::Maximum,
}),
}
);
assert_eq!(PROVIDED4.parse::<Packet>().unwrap().version_sum(), 16);
assert_eq!(PROVIDED5.parse::<Packet>().unwrap().version_sum(), 12);
assert_eq!(PROVIDED6.parse::<Packet>().unwrap().version_sum(), 23);
assert_eq!(PROVIDED7.parse::<Packet>().unwrap().version_sum(), 31);
assert_eq!(PART1_PROVIDED4.parse::<Packet>().unwrap().version_sum(), 16);
assert_eq!(PART1_PROVIDED5.parse::<Packet>().unwrap().version_sum(), 12);
assert_eq!(PART1_PROVIDED6.parse::<Packet>().unwrap().version_sum(), 23);
assert_eq!(PART1_PROVIDED7.parse::<Packet>().unwrap().version_sum(), 31);
}
#[test]
fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 925);
}
const PART2_PROVIDED1: &str = "C200B40A82";
const PART2_PROVIDED2: &str = "04005AC33890";
const PART2_PROVIDED3: &str = "880086C3E88112";
const PART2_PROVIDED4: &str = "CE00C43D881120";
const PART2_PROVIDED5: &str = "D8005AC2A8F0";
const PART2_PROVIDED6: &str = "F600BC2D8F";
const PART2_PROVIDED7: &str = "9C005AC2F8F0";
const PART2_PROVIDED8: &str = "9C0141080250320F1802104A08";
#[test]
fn part2_provided() {
assert_eq!(part2(PART2_PROVIDED1).unwrap(), 3);
assert_eq!(part2(PART2_PROVIDED2).unwrap(), 54);
assert_eq!(part2(PART2_PROVIDED3).unwrap(), 7);
assert_eq!(part2(PART2_PROVIDED4).unwrap(), 9);
assert_eq!(part2(PART2_PROVIDED5).unwrap(), 1);
assert_eq!(part2(PART2_PROVIDED6).unwrap(), 0);
assert_eq!(part2(PART2_PROVIDED7).unwrap(), 0);
assert_eq!(part2(PART2_PROVIDED8).unwrap(), 1);
}
#[test]
fn part2_real() {
assert_eq!(part2(INPUT).unwrap(), 342997120375);
}
}