Improved Day 16 Part 1 by replacing strings with bitvec
This commit is contained in:
parent
2f11a57ec2
commit
f97789eac6
|
@ -5,3 +5,52 @@ version = 3
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aoc2021"
|
name = "aoc2021"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"hex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "0.22.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
|
|
@ -6,6 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bitvec = "0.22.3"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
9C0141080250320F1802104A08
|
A0016C880162017C3686B18A3D4780
|
||||||
|
|
272
src/main.rs
272
src/main.rs
|
@ -1,72 +1,16 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
use bitvec::view::BitView;
|
||||||
|
|
||||||
|
type BitSlice<'a> = &'a bitvec::slice::BitSlice<bitvec::order::Msb0, u8>;
|
||||||
|
|
||||||
const INPUTS: [&'static str; 2] = [
|
const INPUTS: [&'static str; 2] = [
|
||||||
include_str!("../inputs/sample.txt"),
|
include_str!("../inputs/sample.txt"),
|
||||||
include_str!("../inputs/input.txt"),
|
include_str!("../inputs/input.txt"),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn parse_input(input: &'static str) -> String {
|
|
||||||
let mapping = HashMap::from([
|
|
||||||
('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"),
|
|
||||||
]);
|
|
||||||
let input = input.trim();
|
|
||||||
|
|
||||||
let mut out = String::with_capacity(input.len() * 4);
|
|
||||||
|
|
||||||
for c in input.chars() {
|
|
||||||
let v = *mapping.get(&c).unwrap();
|
|
||||||
out.push_str(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_header(s: &mut impl Iterator<Item = char>) -> (u8, u8) {
|
|
||||||
let raw_version: String = s.by_ref().take(3).collect();
|
|
||||||
let version = u8::from_str_radix(&raw_version, 2).unwrap();
|
|
||||||
|
|
||||||
let raw_type_id: String = s.take(3).collect();
|
|
||||||
let type_id = u8::from_str_radix(&raw_type_id, 2).unwrap();
|
|
||||||
|
|
||||||
(version, type_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_literal(input: &mut impl Iterator<Item = char>) -> (u64, u64) {
|
|
||||||
let mut out = String::new();
|
|
||||||
let mut read = 0;
|
|
||||||
loop {
|
|
||||||
let last = input.next().unwrap() == '0';
|
|
||||||
out.extend(input.take(4));
|
|
||||||
read += 5;
|
|
||||||
|
|
||||||
if last {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(u64::from_str_radix(&out, 2).unwrap(), read)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
||||||
struct PacketHeader {
|
struct PacketHeader {
|
||||||
version: u8,
|
version: u8,
|
||||||
type_id: u8,
|
type_id: u8,
|
||||||
|
@ -77,121 +21,148 @@ struct Packet {
|
||||||
header: PacketHeader,
|
header: PacketHeader,
|
||||||
size: u64,
|
size: u64,
|
||||||
literal: Option<u64>,
|
literal: Option<u64>,
|
||||||
|
|
||||||
sub_packets: Vec<Packet>,
|
sub_packets: Vec<Packet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
fn value(&self) -> u64 {
|
fn new(input: &'static str) -> Self {
|
||||||
match self.header.type_id {
|
let out = hex::decode(input).unwrap();
|
||||||
0 => self.sub_packets.iter().fold(0, |a, x| a + x.value()),
|
|
||||||
1 => self.sub_packets.iter().fold(1, |a, x| a * x.value()),
|
|
||||||
2 => self.sub_packets.iter().map(|x| x.value()).min().unwrap(),
|
|
||||||
3 => self.sub_packets.iter().map(|x| x.value()).max().unwrap(),
|
|
||||||
4 => self.literal.unwrap(),
|
|
||||||
5 => {
|
|
||||||
let value1 = self.sub_packets[0].value();
|
|
||||||
let value2 = self.sub_packets[1].value();
|
|
||||||
|
|
||||||
if value1 > value2 {
|
let mut bvec: BitSlice = BitView::view_bits(out.as_slice());
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
6 => {
|
|
||||||
let value1 = self.sub_packets[0].value();
|
|
||||||
let value2 = self.sub_packets[1].value();
|
|
||||||
|
|
||||||
if value1 < value2 {
|
Self::parse(&mut bvec)
|
||||||
1
|
}
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7 => {
|
|
||||||
let value1 = self.sub_packets[0].value();
|
|
||||||
let value2 = self.sub_packets[1].value();
|
|
||||||
|
|
||||||
if value1 == value2 {
|
fn read_literal(ip: &mut BitSlice) -> (u64, u64) {
|
||||||
1
|
let mut out = 0;
|
||||||
} else {
|
let mut read = 0;
|
||||||
0
|
|
||||||
}
|
loop {
|
||||||
|
let (word, remaining) = ip.split_at(5);
|
||||||
|
*ip = remaining;
|
||||||
|
read += 5;
|
||||||
|
|
||||||
|
out = out << 4 | read_as_u8(&word[1..]) as u64;
|
||||||
|
|
||||||
|
if !*word.first().unwrap() {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(out, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_header(ip: &mut BitSlice) -> (u8, u8) {
|
||||||
|
(take_u8(ip, 3), take_u8(ip, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &mut BitSlice) -> Packet {
|
||||||
|
let (version, type_id) = Self::read_header(input);
|
||||||
|
|
||||||
|
let mut out = Packet {
|
||||||
|
size: 6,
|
||||||
|
literal: None,
|
||||||
|
header: PacketHeader { version, type_id },
|
||||||
|
sub_packets: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
match type_id {
|
||||||
|
// Literal
|
||||||
|
4 => {
|
||||||
|
let (literal, read) = Self::read_literal(input);
|
||||||
|
|
||||||
|
out.size += read;
|
||||||
|
out.literal = Some(literal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation
|
||||||
|
_ => {
|
||||||
|
let length_type_id = take_u8(input, 1);
|
||||||
|
out.size += 1;
|
||||||
|
|
||||||
|
match length_type_id {
|
||||||
|
0 => {
|
||||||
|
let mut trailing_packet_size = take_u64(input, 15);
|
||||||
|
out.size += 15;
|
||||||
|
|
||||||
|
while trailing_packet_size > 0 {
|
||||||
|
let packet = Self::parse(input);
|
||||||
|
|
||||||
|
trailing_packet_size -= packet.size;
|
||||||
|
out.size += packet.size;
|
||||||
|
out.sub_packets.push(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1 => {
|
||||||
|
let trailing_packet_count = take_u64(input, 11);
|
||||||
|
out.size += 11;
|
||||||
|
|
||||||
|
for _ in 0..trailing_packet_count {
|
||||||
|
let packet = Self::parse(input);
|
||||||
|
out.size += packet.size;
|
||||||
|
out.sub_packets.push(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_packet(input: &mut impl Iterator<Item = char>) -> Packet {
|
fn take_u8(ip: &mut BitSlice, offset: usize) -> u8 {
|
||||||
let (version, type_id) = read_header(input);
|
let (num, left) = ip.split_at(offset);
|
||||||
|
*ip = left;
|
||||||
|
|
||||||
let mut out = Packet {
|
read_as_u8(num)
|
||||||
size: 6,
|
}
|
||||||
literal: None,
|
|
||||||
header: PacketHeader { version, type_id },
|
|
||||||
sub_packets: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
match type_id {
|
fn take_u64(ip: &mut BitSlice, offset: usize) -> u64 {
|
||||||
// Literal
|
let (num, left) = ip.split_at(offset);
|
||||||
4 => {
|
*ip = left;
|
||||||
let (literal, read) = read_literal(input);
|
|
||||||
|
|
||||||
out.size += read;
|
read_as_u64(num)
|
||||||
out.literal = Some(literal);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Operation
|
fn read_as_u64(ip: BitSlice) -> u64 {
|
||||||
_ => {
|
let mut out = 0;
|
||||||
let length_type_id = input.next().unwrap();
|
|
||||||
out.size += 1;
|
|
||||||
|
|
||||||
match length_type_id {
|
for bit in ip {
|
||||||
'0' => {
|
out = out << 1 | if *bit { 1 } else { 0 };
|
||||||
let mut trailing_packet_size =
|
}
|
||||||
u64::from_str_radix(&input.take(15).collect::<String>(), 2).unwrap();
|
|
||||||
out.size += 15;
|
|
||||||
|
|
||||||
while trailing_packet_size > 0 {
|
|
||||||
let packet = read_packet(input);
|
|
||||||
|
|
||||||
trailing_packet_size -= packet.size;
|
|
||||||
out.size += packet.size;
|
|
||||||
out.sub_packets.push(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'1' => {
|
|
||||||
let trailing_packet_count =
|
|
||||||
usize::from_str_radix(&input.take(11).collect::<String>(), 2).unwrap();
|
|
||||||
out.size += 11;
|
|
||||||
|
|
||||||
for _ in 0..trailing_packet_count {
|
|
||||||
let packet = read_packet(input);
|
|
||||||
out.size += packet.size;
|
|
||||||
out.sub_packets.push(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solution(input: String) -> u64 {
|
fn read_as_u8(ip: BitSlice) -> u8 {
|
||||||
let mut input = input.chars();
|
let mut out = 0;
|
||||||
let packet = read_packet(&mut input);
|
|
||||||
|
|
||||||
packet.value()
|
for bit in ip {
|
||||||
|
out = out << 1 | if *bit { 1 } else { 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(input: &'static str) -> u64 {
|
||||||
|
let packet = Packet::new(input.trim());
|
||||||
|
|
||||||
|
let mut stack = vec![packet];
|
||||||
|
|
||||||
|
let mut answer = 0;
|
||||||
|
while let Some(packet) = stack.pop() {
|
||||||
|
answer += packet.header.version as u64;
|
||||||
|
|
||||||
|
stack.extend(packet.sub_packets);
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for input in INPUTS {
|
for input in INPUTS {
|
||||||
let input = parse_input(input);
|
|
||||||
let result = solution(input);
|
let result = solution(input);
|
||||||
println!("Result = {}", result);
|
println!("Result = {}", result);
|
||||||
}
|
}
|
||||||
|
@ -199,9 +170,8 @@ fn main() {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn solution_bench(b: &mut test::Bencher) {
|
fn solution_bench(b: &mut test::Bencher) {
|
||||||
let input = parse_input(INPUTS[1]);
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let result = solution(input.clone());
|
let result = solution(INPUTS[1]);
|
||||||
test::black_box(result);
|
test::black_box(result);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue