diff options
| author | Reiner Herrmann <reiner@reiner-h.de> | 2020-12-08 18:44:56 +0100 |
|---|---|---|
| committer | Reiner Herrmann <reiner@reiner-h.de> | 2020-12-08 18:44:56 +0100 |
| commit | 1edc5c3013753693d04b1a1adc1ae1b8eef8fdda (patch) | |
| tree | 5c827a12e26f3f9e253f594253095a4119533b10 /src/main.rs | |
| parent | 6cf478a702c48abd23bcbe6fae429d816714a68e (diff) | |
day8
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 131 |
1 files changed, 130 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs index 97c6bdd..635a672 100644 --- a/src/main.rs +++ b/src/main.rs @@ -470,8 +470,118 @@ fn day7() { } +#[derive(Copy, Clone, Debug)] +enum Instruction { + NOP(i32), + ACC(i32), + JMP(i32), +} + +impl Instruction { + fn new(input: &str) -> Instruction { + let operands : Vec<&str> = input.split(' ').collect(); + let (instruction, operand) = (operands[0], operands[1].parse::<i32>().unwrap()); + match instruction { + "nop" => Instruction::NOP(operand), + "acc" => Instruction::ACC(operand), + "jmp" => Instruction::JMP(operand), + _ => panic!("unsupported instruction: {}", instruction), + } + } +} + +struct GameConsole { + instructions: Vec<Instruction>, + acc: i32, + pc: i32, +} + +impl GameConsole { + fn new(input: &[String]) -> GameConsole { + let mut instructions = Vec::new(); + for line in input { + instructions.push(Instruction::new(&line)); + } + GameConsole { + instructions, + acc: 0, + pc: 0, + } + } + + fn step(&mut self) { + let instruction = self.instructions[self.pc as usize]; + match instruction { + Instruction::NOP(_) => { + self.pc += 1; + }, + Instruction::ACC(val) => { + self.acc += val; + self.pc += 1; + } + Instruction::JMP(val) => { + self.pc += val; + } + } + } + + fn find_loop(&mut self) -> Option<i32> { + let mut visited = HashSet::new(); + loop { + let old_acc = self.acc; + self.step(); + if self.pc >= self.instructions.len() as i32 { + return None; + } + if visited.contains(&self.pc) { + return Some(old_acc); + } + visited.insert(self.pc); + } + } + + fn terminates(&mut self) -> bool { + self.find_loop().is_none() + } + + fn reset(&mut self) { + self.acc = 0; + self.pc = 0; + } + + fn repair(&mut self) -> i32 { + for (idx, instruction) in self.instructions.iter().enumerate() { + let replacement = match instruction { + Instruction::NOP(val) => Instruction::JMP(*val), + Instruction::ACC(_) => continue, + Instruction::JMP(val) => Instruction::NOP(*val), + }; + let mut console = GameConsole { + instructions: self.instructions.clone(), + acc: 0, + pc: 0, + }; + console.instructions[idx] = replacement; + if console.terminates() { + return console.acc; + } + } + panic!("nothing found"); + } +} + +fn day8() { + let input = read_lines("input08"); + let mut console = GameConsole::new(&input); + + println!("8a: {}", console.find_loop().unwrap()); + + console.reset(); + println!("8b: {}", console.repair()); +} + fn main() { - day7(); + day8(); } #[cfg(test)] @@ -629,4 +739,23 @@ mod tests { println!("bags: {:?}", bags); assert_eq!(count_contained_bags(&bags, "shiny gold") - 1, 126); } + + #[test] + fn test_day8() { + let input = "nop +0\n\ + acc +1\n\ + jmp +4\n\ + acc +3\n\ + jmp -3\n\ + acc -99\n\ + acc +1\n\ + jmp -4\n\ + acc +6\n"; + let input = read_lines_str(input); + let mut console = GameConsole::new(&input); + assert_eq!(console.find_loop().unwrap(), 5); + + console.reset(); + assert_eq!(console.repair(), 8); + } } |
