use std::error::Error; use std::fs::File; use std::io::{self, BufRead}; use std::vec::Vec; fn expand_digits(line: &str) -> Vec { 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), } 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 = 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 = 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 = 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> { 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(()) }