Advertisement
Guest User

AoC 2020 Day 8 Solution

a guest
Dec 8th, 2020
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 3.71 KB | None | 0 0
  1. use std::fs;
  2.  
  3. const INPUT_PATH: &str = "day8.input";
  4.  
  5. #[derive(Debug, Clone, Copy)]
  6. enum Instr {
  7.     Acc(i64),
  8.     Jmp(i64),
  9.     Nop(i64),
  10. }
  11.  
  12. fn main() {
  13.     let input_str = fs::read_to_string(INPUT_PATH).unwrap();
  14.     let input_str = input_str.trim();
  15.  
  16.     let mut instructions = parse_input(&input_str);
  17.     println!("got {} instructions", instructions.len());
  18.  
  19.    
  20.     // Part 1
  21.     println!("p1: {}", part1(&instructions).1);
  22.  
  23.     // Part 2
  24.     println!("p2: {}", part2(&mut instructions).unwrap());
  25. }
  26.  
  27. // Does the same this as part 1, but also keeps
  28. // track of which nops and which jmps were ran
  29. // last. After this, swaps those out in FILO or-
  30. // -der until the program terminates normally.
  31. fn part2(instrs: &mut Vec<Instr>) -> Option<i64> {
  32.     let mut accum = 0;
  33.     let mut ip: i64 = 0;
  34.    
  35.     let mut lines_executed = Vec::new();
  36.  
  37.     let mut jmps_or_nops = Vec::new();
  38.  
  39.     while (ip as usize) < instrs.len() {
  40.         if lines_executed.contains(&ip) { break; }        
  41.  
  42.         let cur_instr = &instrs[ip as usize];
  43.         lines_executed.push(ip);
  44.  
  45.         match cur_instr {
  46.             Instr::Nop(_) => {
  47.                 jmps_or_nops.push(ip as usize);
  48.                 ip += 1;
  49.             },
  50.             Instr::Acc(i) => {
  51.                 accum += i;
  52.                 ip += 1;
  53.             },
  54.             Instr::Jmp(i) => {
  55.                 jmps_or_nops.push(ip as usize);
  56.                 ip += i;
  57.             }
  58.         }
  59.     }
  60.    
  61.     let mut count = 0;
  62.     // Tha cool stuff
  63.     while !jmps_or_nops.is_empty() {
  64.         let idx = jmps_or_nops.pop().unwrap();
  65.         count += 1;
  66.  
  67.         match instrs[idx] {
  68.             Instr::Nop(val) => instrs[idx] = Instr::Jmp(val),
  69.             Instr::Jmp(val) => instrs[idx] = Instr::Nop(val),
  70.             _ => (),
  71.         }
  72.  
  73.         let (no_loop, accum) = part1(&instrs);
  74.         if no_loop {
  75.             println!("got part 2 solution in {} cycles", count);
  76.             return Some(accum);
  77.         }
  78.        
  79.         match instrs[idx] {
  80.             Instr::Nop(val) => instrs[idx] = Instr::Jmp(val),
  81.             Instr::Jmp(val) => instrs[idx] = Instr::Nop(val),
  82.             _ => (),
  83.         }
  84.  
  85.     }
  86.    
  87.     None
  88. }
  89.  
  90. // Run each instruction, stopping when there's
  91. // an instruction run twice or it reaches the end.
  92. // Returns a tuple containing a bool indicating
  93. // `true` if it did not have any instruction run
  94. // twice and `false` if otherwise. The second item
  95. // in the tuple is the accumulator when it the
  96. // program was stopped.
  97. fn part1(instrs: &Vec<Instr>) -> (bool, i64) {
  98.     let mut accum = 0;
  99.     let mut ip: i64 = 0;
  100.  
  101.     let mut lines_executed = Vec::new();
  102.  
  103.     while (ip as usize) < instrs.len() {
  104.         if lines_executed.contains(&ip) { return (false, accum); }        
  105.  
  106.         let cur_instr = &instrs[ip as usize];
  107.         lines_executed.push(ip);
  108.  
  109.  
  110.         match cur_instr {
  111.             Instr::Nop(_) => ip += 1,
  112.             Instr::Acc(i) => {
  113.                 accum += i;
  114.                 ip += 1;
  115.             },
  116.             Instr::Jmp(i) => ip += i,
  117.         }
  118.     }
  119.  
  120.     (true, accum)
  121. }
  122.  
  123. // Parse input into a list of instructions
  124. fn parse_input(input: &str) -> Vec<Instr> {
  125.     let mut res = Vec::new();
  126.    
  127.     for line in input.split("\n") {
  128.         let mut parts = line.split(" ");
  129.  
  130.         let instr = parts.next().unwrap().trim();
  131.  
  132.         let val = parts.next().unwrap().trim().parse::<i64>().unwrap();
  133.  
  134.         if instr.contains("nop") {
  135.             res.push(Instr::Nop(val));
  136.         } else if instr.contains("acc") {
  137.             res.push(Instr::Acc(val));
  138.         } else if instr.contains("jmp") {
  139.             res.push(Instr::Jmp(val));
  140.         }
  141.  
  142.     }
  143.     res
  144. }
  145.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement