From 90561f8fa9e2e5d75aab60e4a33b303844952dd6 Mon Sep 17 00:00:00 2001 From: Andrew Glaze Date: Thu, 28 Dec 2023 13:35:39 -0500 Subject: [PATCH] day8 --- src/day8.rs | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 181 insertions(+) create mode 100644 src/day8.rs diff --git a/src/day8.rs b/src/day8.rs new file mode 100644 index 0000000..0d4856e --- /dev/null +++ b/src/day8.rs @@ -0,0 +1,180 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::Itertools; +#[aoc_generator(day8)] +fn parse(input: &str) -> Box<[Instruction]> { + let input: Vec = input.lines() + .map(|line| { + let (instruction, arg) = line.split(' ').collect_tuple().unwrap(); + (instruction, arg.parse::().unwrap()).into() + }).collect_vec(); + input.try_into().unwrap() +} + +use Instruction::*; +#[derive(Debug, Clone, Copy)] +enum Instruction { + ACC(i32), + JMP(i32), + NOP(i32) +} + +impl From<(&str, i32)> for Instruction { + fn from(value: (&str, i32)) -> Self { + match value { + (i, v) if i == "acc" => ACC(v), + (i, v) if i == "jmp" => JMP(v), + (i, v) if i == "nop" => NOP(v), + _ => unreachable!() + } + } +} + +#[aoc(day8, part1)] +fn part1(input: &[Instruction]) -> i32 { + let mut visited: Vec = vec![false; input.len()]; + let mut next = 0; + let mut acc = 0; + + loop { + let inst = &input[next]; + if visited[next] { + break; + } + visited[next] = true; + + match inst { + ACC(arg) => acc += arg, + JMP(arg) => {next = (next as i32 + *arg) as usize; continue;}, + NOP(_) => {}, + } + next += 1; + } + + acc +} + +#[aoc(day8, part2)] +fn part2(input: &[Instruction]) -> i32 { + let mut visited: Vec = vec![false; input.len()]; + let mut next = 0; + let mut acc = 0; + + loop { + let inst = &input[next]; + if visited[next] { + break; + } + visited[next] = true; + + match inst { + ACC(arg) => acc += arg, + JMP(arg) => {next = (next as i32 + *arg) as usize; continue;}, + NOP(_) => {}, + } + next += 1; + } + + let mut landing_spots = vec![false; input.len() + 1]; + let mut i = input.len(); + + loop { + landing_spots[i] = true; + i -= 1; + + if let JMP(x) = input[i] { + if x < 0 { + break; + } + } + } + + let start = i; + let swap = if visited[i] { + i + } else { + loop { + i -= 1; + + if landing_spots[i] { + continue; + } else if let NOP(x) = input[i] { + if visited[i] && landing_spots[((i as i32) + x) as usize] { + break i; + } + } else if let JMP(x) = input[i] { + if !visited[i] + && landing_spots[((i as i32) + x) as usize] + && !landing_spots[i] + { + let mut j = i - 1; + loop { + if matches!(input[j], JMP(_)) { + break; + } + j -= 1; + } + + if visited[j] { + break j; + } else { + landing_spots[j + 1..=i].iter_mut().for_each(|a| { + *a = true; + }); + i = start; + } + } + } + } + }; + + let mut program = input.to_vec(); + program[swap] = match program[swap] { + ACC(_) => unreachable!(), + JMP(x) => NOP(x), + NOP(x) => JMP(x), + }; + + let mut next = 0; + let mut acc = 0; + + loop { + if next >= program.len() { + break; + } + let inst = &program[next]; + + match inst { + ACC(arg) => acc += arg, + JMP(arg) => {next = (next as i32 + *arg) as usize; continue;}, + NOP(_) => {}, + } + next += 1; + } + acc +} + + +#[cfg(test)] +mod tests { + use super::*; + +const EX: &str = r"nop +0 +acc +1 +jmp +4 +acc +3 +jmp -3 +acc -99 +acc +1 +jmp -4 +acc +6"; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EX)), 5); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EX)), 8); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f122e7e..92fec11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod day8; mod day7; mod day6; mod day5;