Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::env;
- use std::io::{self};
- #[derive(Debug)]
- enum PacketKind {
- Literal,
- Operator(i64),
- }
- impl PacketKind {
- fn from(version: i64) -> Self {
- match version {
- 4 => PacketKind::Literal,
- z @ (0 | 1 | 2 | 3 | 5 | 6 | 7) => PacketKind::Operator(z),
- _ => unreachable!(),
- }
- }
- }
- enum LengthType {
- Unapplicable,
- LengthInBits(usize),
- NumberOfSubpackets(usize),
- }
- fn parse_packets(s: &str) -> (String,i64,i64) {
- let mut code = String::from(s);
- // Packet header
- let version = b2i(code[0..3].to_string());
- let ptype = b2i(code[3..6].to_string());
- let ptype = PacketKind::from(ptype);
- code = code[6..].to_string();
- // Packet properties
- let mut version_sum = version;
- let mut literal: i64 = 0;
- let mut subpackets: Vec<i64> = Vec::new();
- // Determine packet length type
- let ltype = match ptype {
- PacketKind::Operator(_) => {
- match code[0..1].parse::<u8>().unwrap() {
- 0 => {
- let len = b2i(code[1..=15].to_string()) as usize;
- code = code[16..].to_string();
- LengthType::LengthInBits(len)
- },
- 1 => {
- let len = b2i(code[1..=11].to_string()) as usize;
- code = code[12..].to_string();
- LengthType::NumberOfSubpackets(len)
- },
- _ => unreachable!(),
- }
- },
- _ => LengthType::Unapplicable,
- };
- // Process packet or get subpackets
- match ptype {
- PacketKind::Literal => {
- // Parse literal value
- let mut literal_str: String = String::new();
- 'literal_scan: loop {
- let chunk = code[0..5].to_string();
- literal_str.push_str(&chunk[1..]);
- code = code[5..].to_string();
- if chunk[0..1] == "0".to_string() { break 'literal_scan; }
- }
- literal = b2i(literal_str);
- },
- PacketKind::Operator(_) => {
- // Collect subpackets
- match <ype {
- LengthType::LengthInBits(len) => {
- // Parse next *len* bits
- let mut remain = code[0..*len].to_string();
- while remain.len() > 0 {
- let (sub_remain,sub_version,sub_value) = parse_packets(&remain);
- subpackets.push(sub_value);
- remain = sub_remain.clone();
- version_sum += sub_version;
- }
- code = code[*len..].to_string();
- },
- LengthType::NumberOfSubpackets(num) => {
- // Parse *num* subpackets
- let mut collected = 0;
- while collected < *num {
- let (sub_remain,sub_version,sub_value) = parse_packets(&code);
- subpackets.push(sub_value);
- code = sub_remain.clone();
- version_sum += sub_version;
- collected += 1;
- }
- },
- _ => {},
- }
- }
- }
- // Process packet operations on subpackets
- let value: i64 = match ptype {
- PacketKind::Operator(op) => {
- match op {
- 0 => subpackets.iter().sum::<i64>(), // sum
- 1 => subpackets.iter().product::<i64>(), // product
- 2 => *subpackets.iter().min().unwrap(), //min
- 3 => *subpackets.iter().max().unwrap(), // max
- 5 => if subpackets[0] > subpackets[1] { 1 } else { 0 }, // greater than
- 6 => if subpackets[0] < subpackets[1] { 1 } else { 0 }, // less than
- 7 => if subpackets[0] == subpackets[1] { 1 } else { 0 }, // equal to
- other => panic!("Unknown operation type: {}", other),
- }
- },
- PacketKind::Literal => { literal },
- };
- // Returned values
- (code.to_string(),version_sum,value)
- }
- fn b2i(s: String) -> i64 {
- i64::from_str_radix(&s, 2).unwrap()
- }
- fn h2b(s: String) -> String {
- s.chars().map(|ch| {
- match ch {
- '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",
- _ => unreachable!(),
- }})
- .collect::<String>()
- }
- fn solve(input: &str) -> io::Result<()> {
- // Input
- let input_str = std::fs::read_to_string(input).unwrap();
- let input_str = input_str.trim();
- // Part 1
- let (_,part1,part2) = parse_packets(&h2b(input_str.to_string()));
- println!("Part 1: {}", part1); // 873
- println!("Part 2: {}", part2); // 402817863665
- Ok(())
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let filename = &args[1];
- solve(&filename).unwrap();
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- fn test_hex_p1(hex: String) -> i64 {
- let converted = h2b(hex);
- let (_,part1,_) = parse_packets(&converted);
- part1
- }
- #[test]
- fn test1() {
- let input = "8A004A801A8002F478".to_string();
- let part1 = test_hex_p1(input);
- assert!(part1 == 16)
- }
- #[test]
- fn test2() {
- let input = "620080001611562C8802118E34".to_string();
- let part1 = test_hex_p1(input);
- assert!(part1 == 12)
- }
- #[test]
- fn test3() {
- let input = "C0015000016115A2E0802F182340".to_string();
- let part1 = test_hex_p1(input);
- assert!(part1 == 23)
- }
- #[test]
- fn test4() {
- let input = "A0016C880162017C3686B18A3D4780".to_string();
- let part1 = test_hex_p1(input);
- assert!(part1 == 31)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement