Added Solution for 2021 day 16
This commit is contained in:
parent
b9d666f5c7
commit
cda358ee23
5 changed files with 350 additions and 0 deletions
8
2021/day16_packet_decoder/Cargo.toml
Normal file
8
2021/day16_packet_decoder/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "day16_packet_decoder"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
107
2021/day16_packet_decoder/challenge.txt
Normal file
107
2021/day16_packet_decoder/challenge.txt
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
As you leave the cave and reach open waters, you receive a transmission from the Elves back on the ship.
|
||||||
|
|
||||||
|
The transmission was sent using the Buoyancy Interchange Transmission System (BITS), a method of packing numeric expressions into a binary sequence. Your submarine's computer has saved the transmission in [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) (your puzzle input).
|
||||||
|
|
||||||
|
The first step of decoding the message is to convert the hexadecimal representation into binary. Each character of hexadecimal corresponds to four bits of binary data:
|
||||||
|
|
||||||
|
```
|
||||||
|
0 = 0000
|
||||||
|
1 = 0001
|
||||||
|
2 = 0010
|
||||||
|
3 = 0011
|
||||||
|
4 = 0100
|
||||||
|
5 = 0101
|
||||||
|
6 = 0110
|
||||||
|
7 = 0111
|
||||||
|
8 = 1000
|
||||||
|
9 = 1001
|
||||||
|
A = 1010
|
||||||
|
B = 1011
|
||||||
|
C = 1100
|
||||||
|
D = 1101
|
||||||
|
E = 1110
|
||||||
|
F = 1111
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The BITS transmission contains a single *packet* at its outermost layer which itself contains many other packets. The hexadecimal representation of this packet might encode a few extra `0` bits at the end; these are not part of the transmission and should be ignored.
|
||||||
|
|
||||||
|
Every packet begins with a standard header: the first three bits encode the packet *version*, and the next three bits encode the packet *type ID*. These two values are numbers; all numbers encoded in any packet are represented as binary with the most significant bit first. For example, a version encoded as the binary sequence `100` represents the number `4`.
|
||||||
|
|
||||||
|
Packets with type ID `4` represent a *literal value*. Literal value packets encode a single binary number. To do this, the binary number is padded with leading zeroes until its length is a multiple of four bits, and then it is broken into groups of four bits. Each group is prefixed by a `1` bit except the last group, which is prefixed by a `0` bit. These groups of five bits immediately follow the packet header. For example, the hexadecimal string `D2FE28` becomes:
|
||||||
|
|
||||||
|
```
|
||||||
|
110100101111111000101000
|
||||||
|
VVVTTTAAAAABBBBBCCCCC
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Below each bit is a label indicating its purpose:
|
||||||
|
|
||||||
|
* The three bits labeled `V` (`110`) are the packet version, `6`.
|
||||||
|
* The three bits labeled `T` (`100`) are the packet type ID, `4`, which means the packet is a literal value.
|
||||||
|
* The five bits labeled `A` (`10111`) start with a `1` (not the last group, keep reading) and contain the first four bits of the number, `0111`.
|
||||||
|
* The five bits labeled `B` (`11110`) start with a `1` (not the last group, keep reading) and contain four more bits of the number, `1110`.
|
||||||
|
* The five bits labeled `C` (`00101`) start with a `0` (last group, end of packet) and contain the last four bits of the number, `0101`.
|
||||||
|
* The three unlabeled `0` bits at the end are extra due to the hexadecimal representation and should be ignored.
|
||||||
|
|
||||||
|
So, this packet represents a literal value with binary representation `011111100101`, which is `2021` in decimal.
|
||||||
|
|
||||||
|
Every other type of packet (any packet with a type ID other than `4`) represent an *operator* that performs some calculation on one or more sub-packets contained within. Right now, the specific operations aren't important; focus on parsing the hierarchy of sub-packets.
|
||||||
|
|
||||||
|
An operator packet contains one or more packets. To indicate which subsequent binary data represents its sub-packets, an operator packet can use one of two modes indicated by the bit immediately after the packet header; this is called the *length type ID*:
|
||||||
|
|
||||||
|
* If the length type ID is `0`, then the next *15* bits are a number that represents the *total length in bits* of the sub-packets contained by this packet.
|
||||||
|
* If the length type ID is `1`, then the next *11* bits are a number that represents the *number of sub-packets immediately contained* by this packet.
|
||||||
|
|
||||||
|
Finally, after the length type ID bit and the 15-bit or 11-bit field, the sub-packets appear.
|
||||||
|
|
||||||
|
For example, here is an operator packet (hexadecimal string `38006F45291200`) with length type ID `0` that contains two sub-packets:
|
||||||
|
|
||||||
|
```
|
||||||
|
00111000000000000110111101000101001010010001001000000000
|
||||||
|
VVVTTTILLLLLLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBBBBBB
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
* The three bits labeled `V` (`001`) are the packet version, `1`.
|
||||||
|
* The three bits labeled `T` (`110`) are the packet type ID, `6`, which means the packet is an operator.
|
||||||
|
* The bit labeled `I` (`0`) is the length type ID, which indicates that the length is a 15-bit number representing the number of bits in the sub-packets.
|
||||||
|
* The 15 bits labeled `L` (`000000000011011`) contain the length of the sub-packets in bits, `27`.
|
||||||
|
* The 11 bits labeled `A` contain the first sub-packet, a literal value representing the number `10`.
|
||||||
|
* The 16 bits labeled `B` contain the second sub-packet, a literal value representing the number `20`.
|
||||||
|
|
||||||
|
After reading 11 and 16 bits of sub-packet data, the total length indicated in `L` (27) is reached, and so parsing of this packet stops.
|
||||||
|
|
||||||
|
As another example, here is an operator packet (hexadecimal string `EE00D40C823060`) with length type ID `1` that contains three sub-packets:
|
||||||
|
|
||||||
|
```
|
||||||
|
11101110000000001101010000001100100000100011000001100000
|
||||||
|
VVVTTTILLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBCCCCCCCCCCC
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
* The three bits labeled `V` (`111`) are the packet version, `7`.
|
||||||
|
* The three bits labeled `T` (`011`) are the packet type ID, `3`, which means the packet is an operator.
|
||||||
|
* The bit labeled `I` (`1`) is the length type ID, which indicates that the length is a 11-bit number representing the number of sub-packets.
|
||||||
|
* The 11 bits labeled `L` (`00000000011`) contain the number of sub-packets, `3`.
|
||||||
|
* The 11 bits labeled `A` contain the first sub-packet, a literal value representing the number `1`.
|
||||||
|
* The 11 bits labeled `B` contain the second sub-packet, a literal value representing the number `2`.
|
||||||
|
* The 11 bits labeled `C` contain the third sub-packet, a literal value representing the number `3`.
|
||||||
|
|
||||||
|
After reading 3 complete sub-packets, the number of sub-packets indicated in `L` (3) is reached, and so parsing of this packet stops.
|
||||||
|
|
||||||
|
For now, parse the hierarchy of the packets throughout the transmission and *add up all of the version numbers*.
|
||||||
|
|
||||||
|
Here are a few more examples of hexadecimal-encoded transmissions:
|
||||||
|
|
||||||
|
* `8A004A801A8002F478` represents an operator packet (version 4) which contains an operator packet (version 1) which contains an operator packet (version 5) which contains a literal value (version 6); this packet has a version sum of `*16*`.
|
||||||
|
* `620080001611562C8802118E34` represents an operator packet (version 3) which contains two sub-packets; each sub-packet is an operator packet that contains two literal values. This packet has a version sum of `*12*`.
|
||||||
|
* `C0015000016115A2E0802F182340` has the same structure as the previous example, but the outermost packet uses a different length type ID. This packet has a version sum of `*23*`.
|
||||||
|
* `A0016C880162017C3686B18A3D4780` is an operator packet that contains an operator packet that contains an operator packet that contains five literal values; it has a version sum of `*31*`.
|
||||||
|
|
||||||
|
Decode the structure of your hexadecimal-encoded BITS transmission; *what do you get if you add up the version numbers in all packets?*
|
||||||
|
|
||||||
|
To begin, [get your puzzle input](16/input).
|
||||||
|
|
||||||
|
Answer:
|
222
2021/day16_packet_decoder/src/lib.rs
Normal file
222
2021/day16_packet_decoder/src/lib.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
use core::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum ParseError {
|
||||||
|
PacketTooShort(String),
|
||||||
|
ParseIntError(char),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::PacketTooShort(v) => write!(f, "Packet is too short: {v}"),
|
||||||
|
Self::ParseIntError(c) => write!(f, "Unable to parse {c} into integer"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum PacketValue {
|
||||||
|
Sum(Vec<Packet>),
|
||||||
|
Mul(Vec<Packet>),
|
||||||
|
Min(Vec<Packet>),
|
||||||
|
Max(Vec<Packet>),
|
||||||
|
Literal(usize),
|
||||||
|
Greater(Vec<Packet>),
|
||||||
|
Less(Vec<Packet>),
|
||||||
|
Equal(Vec<Packet>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketValue {
|
||||||
|
fn from(type_id: u8, sub_packets: Vec<Packet>) -> Self {
|
||||||
|
match type_id {
|
||||||
|
0 => Self::Sum(sub_packets),
|
||||||
|
1 => Self::Mul(sub_packets),
|
||||||
|
2 => Self::Min(sub_packets),
|
||||||
|
3 => Self::Max(sub_packets),
|
||||||
|
5 => Self::Greater(sub_packets),
|
||||||
|
6 => Self::Less(sub_packets),
|
||||||
|
7 => Self::Equal(sub_packets),
|
||||||
|
_ => panic!("Unexpected type id: {type_id}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn packets(&self) -> &Vec<Packet> {
|
||||||
|
match self {
|
||||||
|
PacketValue::Literal(_) => panic!("Tried to access packets of literal {self:?}"),
|
||||||
|
PacketValue::Sum(p) => p,
|
||||||
|
PacketValue::Mul(p) => p,
|
||||||
|
PacketValue::Min(p) => p,
|
||||||
|
PacketValue::Max(p) => p,
|
||||||
|
PacketValue::Greater(p) => p,
|
||||||
|
PacketValue::Less(p) => p,
|
||||||
|
PacketValue::Equal(p) => p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Packet {
|
||||||
|
version: u8,
|
||||||
|
value: PacketValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&Vec<bool>> for Packet {
|
||||||
|
type Error = ParseError;
|
||||||
|
|
||||||
|
fn try_from(value: &Vec<bool>) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self::parse(value)?.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet {
|
||||||
|
fn parse(value: &[bool]) -> Result<(Self, usize), ParseError> {
|
||||||
|
if value.len() < 6 {
|
||||||
|
return Err(ParseError::PacketTooShort(format!("{value:?}")));
|
||||||
|
}
|
||||||
|
let version = from_bits(&value[0..3]);
|
||||||
|
let type_id = from_bits(&value[3..6]);
|
||||||
|
if type_id == 4 {
|
||||||
|
let (value, size) = decode_value(&value[6..]);
|
||||||
|
|
||||||
|
Ok((Self {
|
||||||
|
version,
|
||||||
|
value: PacketValue::Literal(value),
|
||||||
|
}, size+6))
|
||||||
|
} else {
|
||||||
|
let length_type = if value[6] {
|
||||||
|
11
|
||||||
|
} else {
|
||||||
|
15
|
||||||
|
};
|
||||||
|
let mut next_idx = 7+length_type;
|
||||||
|
let length = from_bits(&value[7..next_idx]);
|
||||||
|
let mut sub_packets = Vec::new();
|
||||||
|
if length_type == 11 {
|
||||||
|
for _ in 0..length {
|
||||||
|
let sub_packet = Self::parse(&value[next_idx..])?;
|
||||||
|
sub_packets.push(sub_packet.0);
|
||||||
|
next_idx += sub_packet.1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let last_idx = next_idx+length;
|
||||||
|
while next_idx < last_idx {
|
||||||
|
let sub_packet = Self::parse(&value[next_idx..last_idx])?;
|
||||||
|
sub_packets.push(sub_packet.0);
|
||||||
|
next_idx += sub_packet.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((Self {
|
||||||
|
version,
|
||||||
|
value: PacketValue::from(type_id, sub_packets),
|
||||||
|
}, next_idx))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum_version_numbers(&self) -> usize {
|
||||||
|
self.version as usize + match &self.value {
|
||||||
|
PacketValue::Literal(_) => 0,
|
||||||
|
op => op.packets().iter().map(|p| p.sum_version_numbers()).sum(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evaluate(&self) -> usize {
|
||||||
|
match &self.value {
|
||||||
|
PacketValue::Literal(v) => *v,
|
||||||
|
PacketValue::Sum(packets) => packets.iter().map(|p| p.evaluate()).sum(),
|
||||||
|
PacketValue::Mul(packets) => packets.iter().map(|p| p.evaluate()).product(),
|
||||||
|
PacketValue::Min(packets) => packets.iter().map(|p| p.evaluate()).min().unwrap(),
|
||||||
|
PacketValue::Max(packets) => packets.iter().map(|p| p.evaluate()).max().unwrap(),
|
||||||
|
PacketValue::Greater(packets) => if packets[0].evaluate() > packets[1].evaluate() { 1 } else { 0 },
|
||||||
|
PacketValue::Less(packets) => if packets[0].evaluate() < packets[1].evaluate() { 1 } else { 0 },
|
||||||
|
PacketValue::Equal(packets) => if packets[0].evaluate() == packets[1].evaluate() { 1 } else { 0 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(input: &str) -> Result<(usize, usize), ParseError> {
|
||||||
|
let bits: Vec<_> = hex_to_bitstream(input)?;
|
||||||
|
let packets = Packet::try_from(&bits)?;
|
||||||
|
let first = packets.sum_version_numbers();
|
||||||
|
let second = packets.evaluate();
|
||||||
|
Ok((first, second))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_to_bitstream(value: &str) -> Result<Vec<bool>, ParseError> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for c in value.chars() {
|
||||||
|
if let Ok(bits) = try_to_bits(c) {
|
||||||
|
res.append(&mut bits.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_to_bits(original_char: char) -> Result<Vec<bool>, ParseError> {
|
||||||
|
if let Some(value) = original_char.to_digit(16) {
|
||||||
|
Ok((0..4).map(|idx| (value & 2_u32.pow(3-idx)) > 0).collect())
|
||||||
|
} else {
|
||||||
|
Err(ParseError::ParseIntError(original_char))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bits<T>(bits: &[bool]) -> T
|
||||||
|
where T: std::ops::Add<Output = T> + std::ops::Shl<Output = T> + std::convert::From<u8> {
|
||||||
|
bits.iter().fold(T::from(0), |acc, cur| acc.shl(T::from(1)) + if *cur { T::from(1) } else { T::from(0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_value(bits: &[bool]) -> (usize, usize) {
|
||||||
|
let mut res = 0;
|
||||||
|
let mut size = 5;
|
||||||
|
|
||||||
|
for c in bits.chunks(5) {
|
||||||
|
res *= 16;
|
||||||
|
res += from_bits::<usize>(&c[1..]);
|
||||||
|
if !c[0] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size += 5;
|
||||||
|
}
|
||||||
|
(res, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
fn read_file(name: &str) -> String {
|
||||||
|
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sample() {
|
||||||
|
let sample_input = read_file("tests/sample_input");
|
||||||
|
let expected = [
|
||||||
|
(16, 15),
|
||||||
|
(12, 46),
|
||||||
|
(23, 46),
|
||||||
|
(31, 54),
|
||||||
|
(14, 3),
|
||||||
|
(8, 54),
|
||||||
|
(15, 7),
|
||||||
|
(11, 9),
|
||||||
|
(13, 1),
|
||||||
|
(19, 0),
|
||||||
|
(16, 0),
|
||||||
|
(20, 1),
|
||||||
|
];
|
||||||
|
for (idx, line) in sample_input.lines().enumerate() {
|
||||||
|
assert_eq!(run(line), Ok(expected[idx]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_challenge() {
|
||||||
|
let challenge_input = read_file("tests/challenge_input");
|
||||||
|
assert_eq!(run(&challenge_input), Ok((891, 673042777597)));
|
||||||
|
}
|
||||||
|
}
|
1
2021/day16_packet_decoder/tests/challenge_input
Normal file
1
2021/day16_packet_decoder/tests/challenge_input
Normal file
|
@ -0,0 +1 @@
|
||||||
|
A20D74AFC6C80CEA7002D4009202C7C00A6830029400F500218080C3002D006CC2018658056E7002DC00C600E75002ED6008EDC00D4003E24A13995080513FA309482649458A054C6E00E6008CEF204BA00B080311B21F4101006E1F414846401A55002F53E9525B845AA7A789F089402997AE3AFB1E6264D772D7345C6008D8026200E41D83B19C001088CB04A294ADD64C0129D818F802727FFF3500793FFF9A801A801539F42200DC3801A39C659ACD3FC6E97B4B1E7E94FC1F440219DAFB5BB1648E8821A4FF051801079C379F119AC58ECC011A005567A6572324D9AE6CCD003639ED7F8D33B8840A666B3C67B51388440193E003413A3733B85F2712DEBB59002B930F32A7D0688010096019375300565146801A194844826BB7132008024C8E4C1A69E66108000D39BAD950802B19839F005A56D9A554E74C08028992E95D802D2764D93B27900501340528A7301F2E0D326F274BCAB00F5009A737540916D9A9D1EA7BD849100425D9E3A9802B800D24F669E7691E19CFFE3AF280803440086C318230DCC01E8BF19E33980331D631C593005E80330919D718EFA0E3233AE31DF41C67F5CB5CAC002758D7355DD57277F6BF1864E9BED0F18031A95DDF99EB7CD64626EF54987AE007CCC3C4AE0174CDAD88E65F9094BC4025FB2B82C6295F04100109263E800FA41792BCED1CC3A233C86600B48FFF5E522D780120C9C3D89D8466EFEA019009C9600A880310BE0C47A100761345E85F2D7E4769240287E80272D3CEFF1C693A5A79DFE38D27CCCA75E5D00803039BFF11F401095F714657DC56300574010936491FBEC1D8A4402234E1E68026200CC5B8FF094401C89D12E14B803325DED2B6EA34CA248F2748834D0E18021339D4F962AB005E78AE75D08050E10066114368EE0008542684F0B40010B8AB10630180272E83C01998803104E14415100623E469821160
|
12
2021/day16_packet_decoder/tests/sample_input
Normal file
12
2021/day16_packet_decoder/tests/sample_input
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
8A004A801A8002F478
|
||||||
|
620080001611562C8802118E34
|
||||||
|
C0015000016115A2E0802F182340
|
||||||
|
A0016C880162017C3686B18A3D4780
|
||||||
|
C200B40A82
|
||||||
|
04005AC33890
|
||||||
|
880086C3E88112
|
||||||
|
CE00C43D881120
|
||||||
|
D8005AC2A8F0
|
||||||
|
F600BC2D8F
|
||||||
|
9C005AC2F8F0
|
||||||
|
9C0141080250320F1802104A08
|
Loading…
Add table
Add a link
Reference in a new issue