diff --git a/src/day7.rs b/src/day7.rs index 0cfaa7e..caa0b98 100644 --- a/src/day7.rs +++ b/src/day7.rs @@ -1,5 +1,5 @@ use aoc_runner_derive::{aoc, aoc_generator}; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, VecDeque}; pub struct Data { fwd: HashMap>, diff --git a/src/day8.rs b/src/day8.rs new file mode 100644 index 0000000..4b6883a --- /dev/null +++ b/src/day8.rs @@ -0,0 +1,118 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use std::collections::HashSet; + +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)] +pub enum Inst { + Acc { value: i64 }, + Jmp { offset: i64 }, + Nop { unused: i64 }, +} +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] +pub struct CPU { + ip: usize, + program: Vec, + acc: i64, +} + +impl From<&str> for Inst { + fn from(inst: &str) -> Self { + let mut inst = inst.split_whitespace(); + let (inst, arg) = ( + inst.next().unwrap(), + inst.next().map(|v| v.parse::().unwrap()), + ); + match inst { + "jmp" => Inst::Jmp { + offset: arg.unwrap(), + }, + "acc" => Inst::Acc { + value: arg.unwrap(), + }, + "nop" => Inst::Nop { + unused: arg.unwrap(), + }, + other => panic!("Invalid instruction: {}", other), + } + } +} + +impl CPU { + fn new(pgm: &Vec) -> Self { + Self { + ip: 0, + program: pgm.clone(), + acc: 0, + } + } + + fn flip(&mut self, idx: usize) { + if let Some(new_inst) = match &self.program[idx] { + Inst::Jmp { offset } => Some(Inst::Nop { unused: *offset }), + Inst::Nop { unused } => Some(Inst::Jmp { offset: *unused }), + _ => None, + } { + self.program[idx] = new_inst; + }; + } + + fn step(&mut self) -> bool { + // println!("{}: {:?} [Acc: {}]",self.ip,inst, self.acc); + match self.program.get(self.ip) { + Some(Inst::Acc { value }) => { + self.acc += value; + } + Some(Inst::Jmp { offset }) => { + self.ip = ((self.ip as i64) + (offset - 1)) as usize; + } + Some(Inst::Nop { .. }) => (), + None => { + return false; + } + } + self.ip += 1; + return true; + } +} + +#[aoc_generator(day8)] +pub fn input_generator(input: &str) -> Vec { + input.trim().lines().map(|l| Inst::from(l.trim())).collect() +} + +#[aoc(day8, part1)] +pub fn solve_part1(input: &Vec) -> usize { + let mut seen = HashSet::new(); + let mut cpu = CPU::new(input); + loop { + seen.insert(cpu.ip); + cpu.step(); + if seen.contains(&cpu.ip) { + break; + } + } + return cpu.acc as usize; +} + +#[aoc(day8, part2)] +pub fn solve_part2(input: &Vec) -> usize { + for (idx, inst) in input.iter().enumerate() { + match inst { + Inst::Nop { .. } | Inst::Jmp { .. } => { + let mut seen = HashSet::new(); + let mut cpu = CPU::new(input); + cpu.flip(idx); + loop { + seen.insert(cpu.ip); + if !cpu.step() { + return cpu.acc as usize; + }; + if seen.contains(&cpu.ip) { + break; + } + } + } + _ => (), + } + } + panic!("Failed to solve part 2"); +} diff --git a/src/lib.rs b/src/lib.rs index b9a72e2..9227115 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,4 +6,5 @@ pub mod day4; pub mod day5; pub mod day6; pub mod day7; +pub mod day8; aoc_lib! { year = 2020 }