Day 16
This commit is contained in:
parent
4a407de45b
commit
c7b9a878ec
|
@ -0,0 +1 @@
|
|||
620D7800996600E43184312CC01A88913E1E180310FA324649CD5B9DA6BFD107003A4FDE9C718593003A5978C00A7003C400A70025400D60259D400B3002880792201B89400E601694804F1201119400C600C144008100340013440021279A5801AE93CA84C10CF3D100875401374F67F6119CA46769D8664E76FC9E4C01597748704011E4D54D7C0179B0A96431003A48ECC015C0068670FA7EF1BC5166CE440239EFC226F228129E8C1D6633596716E7D4840129C4C8CA8017FCFB943699B794210CAC23A612012EB40151006E2D4678A4200EC548CF12E4FDE9BD4A5227C600F80021D08219C1A00043A27C558AA200F4788C91A1002C893AB24F722C129BDF5121FA8011335868F1802AE82537709999796A7176254A72F8E9B9005BD600A4FD372109FA6E42D1725EDDFB64FFBD5B8D1802323DC7E0D1600B4BCDF6649252B0974AE48D4C0159392DE0034B356D626A130E44015BD80213183A93F609A7628537EB87980292A0D800F94B66546896CCA8D440109F80233ABB3ABF3CB84026B5802C00084C168291080010C87B16227CB6E454401946802735CA144BA74CFF71ADDC080282C00546722A1391549318201233003361006A1E419866200DC758330525A0C86009CC6E7F2BA00A4E7EF7AD6E873F7BD6B741300578021B94309ABE374CF7AE7327220154C3C4BD395C7E3EB756A72AC10665C08C010D0046458E72C9B372EAB280372DFE1BCA3ECC1690046513E5D5E79C235498B9002BD132451A5C78401B99AFDFE7C9A770D8A0094EDAC65031C0178AB3D8EEF8E729F2C200D26579BEDF277400A9C8FE43D3030E010C6C9A078853A431C0C0169A5CB00400010F8C9052098002191022143D30047C011100763DC71824200D4368391CA651CC0219C51974892338D0
|
|
@ -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>),
|
||||
}
|
|
@ -14,7 +14,8 @@ mod day12;
|
|||
mod day13;
|
||||
mod day14;
|
||||
mod day15;
|
||||
mod day16;
|
||||
|
||||
fn main() {
|
||||
day15::day15();
|
||||
day16::day16();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue