Skip to content
Snippets Groups Projects
Select Git revision
  • 577cd494b3eaa9f2b63fc4dc2ab1c387ef967a41
  • main default protected
2 results

main.rs

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    main.rs 3.21 KiB
    use std::fs::File;
    use std::io::{self, prelude::*, BufReader};
    
    #[derive(Debug, Clone)]
    struct Instruction {
        operation: Operation,
        argument: i64,
    }
    
    #[derive(Debug, Clone, PartialEq)]
    enum Operation {
        Increment,
        Jump,
        Nothing,
    }
    
    #[derive(Debug, PartialEq)]
    enum Reason {
        LoopDetected,
        Terminated,
    }
    
    impl Instruction {
        fn from_str(input: &str) -> Self {
            let (op, arg) = input.split_at(4);
            let operation = match op {
                "acc " => Operation::Increment,
                "jmp " => Operation::Jump,
                "nop " => Operation::Nothing,
                _ => panic!(),
            };
            let argument = arg.parse::<i64>().unwrap();
            Instruction {
                operation: operation,
                argument: argument,
            }
        }
    
        pub fn apply(&self, accumulator: i64, index: isize) -> (i64, isize) {
            match self.operation {
                Operation::Increment => (accumulator + self.argument, index.checked_add(1).unwrap()),
                Operation::Jump => (accumulator, index.checked_add(self.argument as isize).unwrap()),
                Operation::Nothing => (accumulator, index.checked_add(1).unwrap()),
            }
        }
    }
    
    fn compute(instructions: &Vec<Instruction>) -> (Reason, i64) {
        let mut accumulator = 0;
        let mut index: isize = 0;
    
        let mut visited_indices = vec![];
    
        loop {
            if visited_indices.contains(&index) {
                // prevent looping
                return (Reason::LoopDetected, accumulator);
            }
            visited_indices.push(index);
    
            if index as usize == instructions.len() {
                // code run through
                return (Reason::Terminated, accumulator);
            }
    
            let result = instructions[index as usize].apply(accumulator, index);
            accumulator = result.0;
            index = result.1;
        }
    }
    
    fn main() -> io::Result<()> {
        println!("Advent of Code 2020 – Day 8:");
    
        let file = File::open("input.txt")?;
        let reader = BufReader::new(file);
    
        let instructions = reader
            .lines()
            .map(|l| Instruction::from_str(&l.unwrap()))
            .collect::<Vec<Instruction>>();
    
        let answer1: i64 = compute(&instructions).1;
    
        println!("Answer Part 1: {}", answer1);
    
        let mut answer2: i64 = 100;
    
        for index in 0..(instructions.len()-1) {
            let mut instruction = instructions[index].clone();
            if instruction.operation == Operation::Increment {
                // don't need to change and don't need to run
                continue;
            }
    
            instruction = match instruction.operation {
                Operation::Jump => Instruction {
                    operation: Operation::Nothing,
                    argument: instruction.argument,
                },
                Operation::Nothing => Instruction {
                    operation: Operation::Jump,
                    argument: instruction.argument,
                },
                _ => unimplemented!()
            };
    
            let mut mutated_instructions = instructions.clone();
            mutated_instructions[index] = instruction;
    
            let value = compute(&mutated_instructions);
    
            if value.0 == Reason::Terminated {
                // answer found
                answer2 = value.1;
                break;
            }
    
        }
    
        println!("Answer Part 2: {}", answer2);
    
        Ok(())
    }