This commit is contained in:
Shadowfacts 2021-12-16 14:49:05 -05:00
parent 4a407de45b
commit c7b9a878ec
3 changed files with 243 additions and 1 deletions

1
input/day16.txt Normal file
View File

@ -0,0 +1 @@
620D7800996600E43184312CC01A88913E1E180310FA324649CD5B9DA6BFD107003A4FDE9C718593003A5978C00A7003C400A70025400D60259D400B3002880792201B89400E601694804F1201119400C600C144008100340013440021279A5801AE93CA84C10CF3D100875401374F67F6119CA46769D8664E76FC9E4C01597748704011E4D54D7C0179B0A96431003A48ECC015C0068670FA7EF1BC5166CE440239EFC226F228129E8C1D6633596716E7D4840129C4C8CA8017FCFB943699B794210CAC23A612012EB40151006E2D4678A4200EC548CF12E4FDE9BD4A5227C600F80021D08219C1A00043A27C558AA200F4788C91A1002C893AB24F722C129BDF5121FA8011335868F1802AE82537709999796A7176254A72F8E9B9005BD600A4FD372109FA6E42D1725EDDFB64FFBD5B8D1802323DC7E0D1600B4BCDF6649252B0974AE48D4C0159392DE0034B356D626A130E44015BD80213183A93F609A7628537EB87980292A0D800F94B66546896CCA8D440109F80233ABB3ABF3CB84026B5802C00084C168291080010C87B16227CB6E454401946802735CA144BA74CFF71ADDC080282C00546722A1391549318201233003361006A1E419866200DC758330525A0C86009CC6E7F2BA00A4E7EF7AD6E873F7BD6B741300578021B94309ABE374CF7AE7327220154C3C4BD395C7E3EB756A72AC10665C08C010D0046458E72C9B372EAB280372DFE1BCA3ECC1690046513E5D5E79C235498B9002BD132451A5C78401B99AFDFE7C9A770D8A0094EDAC65031C0178AB3D8EEF8E729F2C200D26579BEDF277400A9C8FE43D3030E010C6C9A078853A431C0C0169A5CB00400010F8C9052098002191022143D30047C011100763DC71824200D4368391CA651CC0219C51974892338D0

240
src/day16.rs Normal file
View File

@ -0,0 +1,240 @@
use std::str::Chars;
use itertools::Itertools;
pub fn day16() {
assert_eq!(
parse_hex_str("D2FE28"),
Packet {
version: 6,
type_id: 4,
length: 21,
payload: Payload::Literal(2021),
},
);
assert_eq!(
parse_hex_str("38006F45291200"),
Packet {
version: 1,
type_id: 6,
length: 49,
payload: Payload::Operator(vec![
Packet {
version: 6,
type_id: 4,
length: 11,
payload: Payload::Literal(10),
},
Packet {
version: 2,
type_id: 4,
length: 16,
payload: Payload::Literal(20),
},
]),
},
);
dbg!(parse_hex_str("EE00D40C823060"));
let sums = &[
"8A004A801A8002F478",
"620080001611562C8802118E34",
"C0015000016115A2E0802F182340",
"A0016C880162017C3686B18A3D4780",
]
.map(|s| parse_hex_str(s).sum_versions());
assert_eq!(sums, &[16, 12, 23, 31]);
let input = include_str!("../input/day16.txt");
let packet = parse_hex_str(input);
println!("part 1: {}", packet.sum_versions());
let values = &[
"C200B40A82",
"04005AC33890",
"880086C3E88112",
"CE00C43D881120",
"D8005AC2A8F0",
"F600BC2D8F",
"9C005AC2F8F0",
"9C0141080250320F1802104A08",
]
.map(|s| parse_hex_str(s).eval());
assert_eq!(values, &[3, 54, 7, 9, 1, 0, 0, 1]);
println!("part 2: {}", packet.eval());
}
fn parse_hex_str(hex_str: &str) -> Packet {
let mut bits = HexToBits::new(hex_str.chars());
parse_packet(&mut bits, 0)
}
fn parse_packet<'a>(bits: &mut HexToBits<'a>, depth: u32) -> Packet {
let mut packet_len = 6;
let version = bits.read(3);
let type_id = bits.read(3);
let payload: Payload;
// println!("type id {} at depth {}", type_id, depth);
if type_id == 4 {
let mut val = 0;
loop {
let is_last = !bits.next().unwrap();
val <<= 4;
val |= bits.read(4);
packet_len += 5;
if is_last {
break;
}
}
payload = Payload::Literal(val);
} else {
packet_len += 1;
let length_type = bits.next().unwrap();
let length = if length_type {
packet_len += 11;
bits.read(11)
} else {
packet_len += 15;
bits.read(15)
};
// println!("length type: {}, length: {}", length_type, length);
let mut sub_packets = vec![];
let mut sub_packets_len = 0;
loop {
if length_type && sub_packets.len() >= length {
break;
} else if !length_type && sub_packets_len >= length {
break;
}
let packet = parse_packet(bits, depth + 1);
sub_packets_len += packet.length;
// println!(
// "read packet of length {} at depth {}",
// packet.length,
// depth + 1
// );
sub_packets.push(packet);
}
payload = Payload::Operator(sub_packets);
packet_len += sub_packets_len;
}
Packet {
version,
type_id,
length: packet_len,
payload,
}
}
struct HexToBits<'a> {
hex_chars: Chars<'a>,
current: u32,
current_bits_remaining: u32,
read_so_far: usize,
}
impl<'a> HexToBits<'a> {
fn new(chars: Chars<'a>) -> Self {
Self {
hex_chars: chars,
current: 0,
current_bits_remaining: 0,
read_so_far: 0,
}
}
fn read(&mut self, len: u32) -> usize {
let mut res = 0;
for _ in 0..len {
res <<= 1;
res |= if self.next().unwrap() { 1 } else { 0 };
}
res
}
}
impl<'a> Iterator for HexToBits<'a> {
type Item = bool;
fn next(&mut self) -> Option<bool> {
if self.current_bits_remaining > 0 {
let res = Some((self.current >> self.current_bits_remaining - 1) & 1 == 1);
self.current_bits_remaining -= 1;
self.read_so_far += 1;
res
} else if let Some(c) = self.hex_chars.next() {
self.current = c.to_digit(16).unwrap();
self.current_bits_remaining = 3;
self.read_so_far += 1;
Some((self.current >> 3) & 1 == 1)
} else {
None
}
}
}
#[derive(Debug, PartialEq)]
struct Packet {
version: usize,
type_id: usize,
length: usize,
payload: Payload,
}
impl Packet {
fn sum_versions(&self) -> usize {
match self.payload {
Payload::Literal(_) => self.version,
Payload::Operator(ref sub) => {
self.version + sub.iter().map(|p| p.sum_versions()).sum::<usize>()
}
}
}
fn eval(&self) -> usize {
match self.payload {
Payload::Literal(n) => n,
Payload::Operator(ref sub) => {
let sub_vals = sub.iter().map(|p| p.eval());
match self.type_id {
0 => sub_vals.sum(),
1 => sub_vals.product(),
2 => sub_vals.min().unwrap(),
3 => sub_vals.max().unwrap(),
5 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a > b {
1
} else {
0
}
}
6 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a < b {
1
} else {
0
}
}
7 => {
let (a, b) = sub_vals.collect_tuple().unwrap();
if a == b {
1
} else {
0
}
}
_ => panic!(),
}
}
}
}
}
#[derive(Debug, PartialEq)]
enum Payload {
Literal(usize),
Operator(Vec<Packet>),
}

View File

@ -14,7 +14,8 @@ mod day12;
mod day13;
mod day14;
mod day15;
mod day16;
fn main() {
day15::day15();
day16::day16();
}