Advertisement
nairby

Day 16 Code

Dec 16th, 2021 (edited)
340
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.26 KB | None | 0 0
  1. use std::env;
  2. use std::io::{self};
  3.  
  4. #[derive(Debug)]
  5. enum PacketKind {
  6.     Literal,
  7.     Operator(i64),
  8. }
  9. impl PacketKind {
  10.     fn from(version: i64) -> Self {
  11.         match version {
  12.             4 => PacketKind::Literal,
  13.             z @ (0 | 1 | 2 | 3 | 5 | 6 | 7) => PacketKind::Operator(z),
  14.             _ => unreachable!(),
  15.         }
  16.     }
  17. }
  18. enum LengthType {
  19.     Unapplicable,
  20.     LengthInBits(usize),
  21.     NumberOfSubpackets(usize),
  22. }
  23.  
  24. fn parse_packets(s: &str) -> (String,i64,i64) {
  25.  
  26.     let mut code = String::from(s);
  27.    
  28.     // Packet header
  29.     let version = b2i(code[0..3].to_string());
  30.     let ptype   = b2i(code[3..6].to_string());
  31.     let ptype   = PacketKind::from(ptype);
  32.     code = code[6..].to_string();
  33.    
  34.     // Packet properties
  35.     let mut version_sum = version;
  36.     let mut literal: i64 = 0;
  37.     let mut subpackets: Vec<i64> = Vec::new();
  38.  
  39.     // Determine packet length type
  40.     let ltype = match ptype {
  41.         PacketKind::Operator(_) => {
  42.             match code[0..1].parse::<u8>().unwrap() {
  43.                 0 => {
  44.                     let len = b2i(code[1..=15].to_string()) as usize;
  45.                     code = code[16..].to_string();
  46.                     LengthType::LengthInBits(len)
  47.                 },
  48.                 1 => {
  49.                     let len = b2i(code[1..=11].to_string()) as usize;
  50.                     code = code[12..].to_string();
  51.                     LengthType::NumberOfSubpackets(len)
  52.                 },
  53.                 _ => unreachable!(),
  54.             }
  55.         },
  56.         _ => LengthType::Unapplicable,
  57.     };
  58.  
  59.     // Process packet or get subpackets
  60.     match ptype {
  61.         PacketKind::Literal => {
  62.             // Parse literal value
  63.             let mut literal_str: String = String::new();
  64.             'literal_scan: loop {
  65.                let chunk = code[0..5].to_string();
  66.                literal_str.push_str(&chunk[1..]);
  67.                code = code[5..].to_string();
  68.                if chunk[0..1] == "0".to_string() { break 'literal_scan; }
  69.             }
  70.             literal = b2i(literal_str);
  71.         },
  72.         PacketKind::Operator(_) => {
  73.             // Collect subpackets
  74.             match &ltype {
  75.                 LengthType::LengthInBits(len) => {
  76.                     // Parse next *len* bits
  77.                     let mut remain = code[0..*len].to_string();
  78.                     while remain.len() > 0 {
  79.                         let (sub_remain,sub_version,sub_value) = parse_packets(&remain);
  80.                         subpackets.push(sub_value);
  81.                         remain = sub_remain.clone();
  82.                         version_sum += sub_version;
  83.                     }
  84.                     code = code[*len..].to_string();
  85.                 },
  86.                 LengthType::NumberOfSubpackets(num) => {
  87.                     // Parse *num* subpackets
  88.                     let mut collected = 0;
  89.                     while collected < *num {
  90.                         let (sub_remain,sub_version,sub_value) = parse_packets(&code);
  91.                         subpackets.push(sub_value);
  92.                         code = sub_remain.clone();
  93.                         version_sum += sub_version;
  94.                         collected += 1;
  95.                     }
  96.                 },
  97.                 _ => {},
  98.             }
  99.         }
  100.     }
  101.  
  102.     // Process packet operations on subpackets
  103.     let value: i64 = match ptype {
  104.         PacketKind::Operator(op) => {
  105.             match op {
  106.                 0 => subpackets.iter().sum::<i64>(),                     // sum
  107.                 1 => subpackets.iter().product::<i64>(),                 // product
  108.                 2 => *subpackets.iter().min().unwrap(),                  //min
  109.                 3 => *subpackets.iter().max().unwrap(),                  // max
  110.                 5 => if subpackets[0] >  subpackets[1] { 1 } else { 0 }, // greater than
  111.                 6 => if subpackets[0] <  subpackets[1] { 1 } else { 0 }, // less than
  112.                 7 => if subpackets[0] == subpackets[1] { 1 } else { 0 }, // equal to
  113.                 other => panic!("Unknown operation type: {}", other),
  114.             }
  115.         },
  116.         PacketKind::Literal => { literal },
  117.     };
  118.    
  119.     // Returned values
  120.     (code.to_string(),version_sum,value)
  121. }
  122.  
  123. fn b2i(s: String) -> i64 {
  124.     i64::from_str_radix(&s, 2).unwrap()
  125. }
  126.  
  127. fn h2b(s: String) -> String {
  128.     s.chars().map(|ch| {
  129.         match ch {
  130.             '0' => "0000",
  131.             '1' => "0001",
  132.             '2' => "0010",
  133.             '3' => "0011",
  134.             '4' => "0100",
  135.             '5' => "0101",
  136.             '6' => "0110",
  137.             '7' => "0111",
  138.             '8' => "1000",
  139.             '9' => "1001",
  140.             'A' => "1010",
  141.             'B' => "1011",
  142.             'C' => "1100",
  143.             'D' => "1101",
  144.             'E' => "1110",
  145.             'F' => "1111",
  146.             _ => unreachable!(),
  147.         }})
  148.     .collect::<String>()
  149. }
  150.  
  151. fn solve(input: &str) -> io::Result<()> {
  152.     // Input
  153.     let input_str = std::fs::read_to_string(input).unwrap();
  154.     let input_str = input_str.trim();
  155.  
  156.     // Part 1
  157.     let (_,part1,part2) = parse_packets(&h2b(input_str.to_string()));
  158.     println!("Part 1: {}", part1); // 873
  159.     println!("Part 2: {}", part2); // 402817863665
  160.  
  161.     Ok(())
  162. }
  163.  
  164. fn main() {
  165.     let args: Vec<String> = env::args().collect();
  166.     let filename = &args[1];
  167.     solve(&filename).unwrap();
  168. }
  169.  
  170. #[cfg(test)]
  171. mod tests {
  172.     use super::*;
  173.     fn test_hex_p1(hex: String) -> i64 {
  174.         let converted = h2b(hex);
  175.         let (_,part1,_) = parse_packets(&converted);
  176.         part1
  177.     }
  178.  
  179.     #[test]
  180.     fn test1() {
  181.         let input = "8A004A801A8002F478".to_string();
  182.         let part1 = test_hex_p1(input);
  183.         assert!(part1 == 16)
  184.     }
  185.  
  186.     #[test]
  187.     fn test2() {
  188.         let input = "620080001611562C8802118E34".to_string();
  189.         let part1 = test_hex_p1(input);
  190.         assert!(part1 == 12)
  191.     }
  192.  
  193.     #[test]
  194.     fn test3() {
  195.         let input = "C0015000016115A2E0802F182340".to_string();
  196.         let part1 = test_hex_p1(input);
  197.         assert!(part1 == 23)
  198.     }
  199.  
  200.     #[test]
  201.     fn test4() {
  202.         let input = "A0016C880162017C3686B18A3D4780".to_string();
  203.         let part1 = test_hex_p1(input);
  204.         assert!(part1 == 31)
  205.     }
  206. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement