M Cargo.lock => Cargo.lock +7 -0
@@ 52,3 52,10 @@ version = "1.0.0"
dependencies = [
"common",
]
+
+[[package]]
+name = "day_08"
+version = "1.0.0"
+dependencies = [
+ "common",
+]
M Cargo.toml => Cargo.toml +2 -1
@@ 7,7 7,8 @@ members = [
"day_04",
"day_05",
"day_06",
- "day_07"
+ "day_07",
+ "day_08"
]
[profile.release]
A day_08/Cargo.toml => day_08/Cargo.toml +12 -0
@@ 0,0 1,12 @@
+[package]
+name = "day_08"
+version = "1.0.0"
+description = "Day 8 - Advent of Code 2020"
+authors = ["Jan Baudisch <jan@baudisch.xyz>"]
+license = "GPL-3.0-or-later"
+readme = "../README.md"
+edition = "2018"
+workspace = ".."
+
+[dependencies]
+common = { path = "../common" }
A day_08/src/code.rs => day_08/src/code.rs +67 -0
@@ 0,0 1,67 @@
+use crate::instruction::Instruction;
+
+#[derive(Clone, Debug)]
+pub struct Code {
+ instructions: Vec<Instruction>,
+ pointer: usize,
+ visited: Vec<usize>,
+ pub accumulator: i32,
+}
+
+impl From<Vec<String>> for Code {
+ fn from(input: Vec<String>) -> Self {
+ let instructions = input.iter().map(|x| x.into()).collect();
+
+ Self {
+ instructions,
+ pointer: 0,
+ visited: Vec::new(),
+ accumulator: 0,
+ }
+ }
+}
+
+impl Code {
+ fn step(&mut self) {
+ self.visited.push(self.pointer);
+
+ let mut pointer = self.pointer as isize;
+
+ match self.instructions[self.pointer] {
+ Instruction::Accumulate(i) => self.accumulator += i,
+ Instruction::Jump(i) => pointer += i as isize - 1,
+ Instruction::Noop(_) => {}
+ }
+
+ self.pointer = pointer as usize + 1;
+ }
+
+ pub fn run(&mut self) {
+ while !self.visited.contains(&self.pointer) && self.pointer < self.instructions.len() {
+ self.step();
+ }
+ }
+
+ pub fn repair(&mut self) {
+ let mut test_pointer = self.instructions.len();
+
+ loop {
+ test_pointer -= 1;
+
+ let mut test = self.clone();
+
+ match test.instructions[test_pointer] {
+ Instruction::Jump(i) => test.instructions[test_pointer] = Instruction::Noop(i),
+ Instruction::Noop(i) => test.instructions[test_pointer] = Instruction::Jump(i),
+ _ => {}
+ }
+
+ test.run();
+
+ if test.pointer == test.instructions.len() {
+ self.instructions = test.instructions;
+ return;
+ }
+ }
+ }
+}
A day_08/src/instruction.rs => day_08/src/instruction.rs +19 -0
@@ 0,0 1,19 @@
+#[derive(Clone, Copy, Debug)]
+pub enum Instruction {
+ Accumulate(i32),
+ Jump(i32),
+ Noop(i32),
+}
+
+impl From<&String> for Instruction {
+ fn from(input: &String) -> Self {
+ let mut parts = input.split_whitespace();
+
+ match parts.next().unwrap() {
+ "acc" => Self::Accumulate(i32::from_str_radix(parts.next().unwrap(), 10).unwrap()),
+ "jmp" => Self::Jump(i32::from_str_radix(parts.next().unwrap(), 10).unwrap()),
+ "nop" => Self::Noop(i32::from_str_radix(parts.next().unwrap(), 10).unwrap()),
+ _ => panic!("error converting input"),
+ }
+ }
+}
A day_08/src/main.rs => day_08/src/main.rs +59 -0
@@ 0,0 1,59 @@
+mod code;
+mod instruction;
+
+use code::Code;
+use common::input;
+
+fn main() {
+ let code: Code = input::read_lines().into();
+
+ let mut part_one = code.clone();
+ part_one.run();
+
+ println!(
+ "[PART ONE] accumulator before loop: {}",
+ part_one.accumulator
+ );
+
+ let mut part_two = code;
+ part_two.repair();
+ part_two.run();
+
+ println!(
+ "[PART TWO] accumulator after termintation: {}",
+ part_two.accumulator
+ );
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Code;
+
+ fn generate_code() -> Code {
+ let input = vec![
+ "nop +0", "acc +1", "jmp +4", "acc +3", "jmp -3", "acc -99", "acc +1", "jmp -4",
+ "acc +6",
+ ];
+
+ input
+ .iter()
+ .map(|x| x.to_string())
+ .collect::<Vec<String>>()
+ .into()
+ }
+
+ #[test]
+ fn part_one() {
+ let mut code = generate_code();
+ code.run();
+ assert_eq!(code.accumulator, 5);
+ }
+
+ #[test]
+ fn part_two() {
+ let mut code = generate_code();
+ code.repair();
+ code.run();
+ assert_eq!(code.accumulator, 8);
+ }
+}