192 lines
5.4 KiB
Rust
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(())
|
||
|
}
|