AoC2021/src/bin/day16.rs

192 lines
5.4 KiB
Rust

use std::error::Error;
use std::fs::File;
use std::io::{self, BufRead};
use std::vec::Vec;
fn expand_digits(line: &str) -> Vec<bool> {
let mut bin = Vec::new();
for c in line.chars() {
let bits = match c {
'0' => [false, false, false, false],
'1' => [false, false, false, true],
'2' => [false, false, true, false],
'3' => [false, false, true, true],
'4' => [false, true, false, false],
'5' => [false, true, false, true],
'6' => [false, true, true, false],
'7' => [false, true, true, true],
'8' => [true, false, false, false],
'9' => [true, false, false, true],
'A' => [true, false, true, false],
'B' => [true, false, true, true],
'C' => [true, true, false, false],
'D' => [true, true, false, true],
'E' => [true, true, true, false],
'F' => [true, true, true, true],
_ => panic!("Unsupported char {}", c),
};
bin.extend_from_slice(&bits);
}
bin
}
fn print_binary(bin: &[bool]) {
for bit in bin.iter() {
if *bit {
print!("1");
} else {
print!("0");
}
}
println!("");
}
fn bits_to_uint(bits: &[bool]) -> u64 {
let mut base = 1;
let mut res = 0;
for bit in bits.iter().rev() {
if *bit {
res += base;
}
base *= 2;
}
res
}
enum Packet {
Literal(u64, u64, u64),
Operator(u64, u64, Vec<Packet>),
}
fn parse_packet(bits: &[bool]) -> (Packet, &[bool]) {
let version = bits_to_uint(&bits[0..3]);
let type_id = bits_to_uint(&bits[3..6]);
println!("Version: {}", version);
println!("Type: {}", type_id);
//Literal value
if type_id == 4 {
let mut tail = &bits[6..];
let mut res: Vec<bool> = Vec::new();
loop {
let chunk = &tail[0..5];
tail = &tail[5..];
res.extend_from_slice(&chunk[1..5]);
if !chunk[0] {
break;
}
}
let literal = bits_to_uint(&res);
println!("Literal {}", literal);
return (Packet::Literal(version, type_id, literal), tail);
} else {
if !bits[6] {
let bit_lenght = bits_to_uint(&bits[7..22]) as usize;
println!("15 bits, bit lenght {}", bit_lenght);
let mut sub_packets = &bits[22..22 + bit_lenght];
let tail = &bits[22 + bit_lenght..];
let mut packets: Vec<Packet> = Vec::new();
while sub_packets.len() >= 11 {
let (packet, rest) = parse_packet(sub_packets);
packets.push(packet);
sub_packets = rest;
}
return (Packet::Operator(version, type_id, packets), tail);
} else {
let packet_lenght = bits_to_uint(&bits[7..18]) as usize;
println!("11 bits, number of packets {}", packet_lenght);
let mut tail = &bits[18..];
let mut packets: Vec<Packet> = Vec::new();
for _ in 0..packet_lenght {
let (packet, rest) = parse_packet(tail);
packets.push(packet);
tail = rest;
}
return (Packet::Operator(version, type_id, packets), tail);
}
}
}
fn add_versions(packet: &Packet) -> u64 {
match packet {
Packet::Literal(version, _, _) => *version,
Packet::Operator(version, _, sub_packets) => {
version
+ sub_packets
.iter()
.map(|p| add_versions(p))
.fold(0, |a, b| a + b)
}
}
}
fn execute_packet(packet: &Packet) -> u64 {
match packet {
Packet::Literal(_, _, value) => *value,
Packet::Operator(_, type_id, sub_packets) => match type_id {
0 => sub_packets
.iter()
.map(|p| execute_packet(p))
.fold(0, |a, b| a + b), // sum
1 => sub_packets
.iter()
.map(|p| execute_packet(p))
.fold(1, |a, b| a * b), // product
2 => sub_packets.iter().map(|p| execute_packet(p)).min().unwrap(), // min
3 => sub_packets.iter().map(|p| execute_packet(p)).max().unwrap(), // max
5 => {
if execute_packet(&sub_packets[0]) > execute_packet(&sub_packets[1]) {
1
} else {
0
}
}
6 => {
if execute_packet(&sub_packets[0]) < execute_packet(&sub_packets[1]) {
1
} else {
0
}
}
7 => {
if execute_packet(&sub_packets[0]) == execute_packet(&sub_packets[1]) {
1
} else {
0
}
}
_ => panic!("Unsupported packet type {}", type_id),
},
}
}
fn main() -> Result<(), Box<dyn Error>> {
let file = File::open("inputs/day16.txt")?;
let line: String = io::BufReader::new(file).lines().next().unwrap()?;
let data = expand_digits(&line);
print_binary(&data);
let (packet, _) = parse_packet(&data);
let answer1 = add_versions(&packet);
println!("Answer1: {}", answer1);
let answer2 = execute_packet(&packet);
println!("Answer2: {}", answer2);
Ok(())
}