Added Solution for 2020 day 08

This commit is contained in:
Burnus 2023-04-04 17:11:41 +02:00
parent 952b646d08
commit b0f42876e7
6 changed files with 895 additions and 0 deletions

View file

@ -0,0 +1,8 @@
[package]
name = "day08_handheld_halting"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,104 @@
Your flight to the major airline hub reaches cruising altitude without incident. While you consider checking the in-flight menu for one of those drinks that come with a little umbrella, you are interrupted by the kid sitting next to you.
Their [handheld game console](https://en.wikipedia.org/wiki/Handheld_game_console) won't turn on! They ask if you can take a look.
You narrow the problem down to a strange *infinite loop* in the boot code (your puzzle input) of the device. You should be able to fix it, but first you need to be able to run the code in isolation.
The boot code is represented as a text file with one *instruction* per line of text. Each instruction consists of an *operation* (`acc`, `jmp`, or `nop`) and an *argument* (a signed number like `+4` or `-20`).
* `acc` increases or decreases a single global value called the *accumulator* by the value given in the argument. For example, `acc +7` would increase the accumulator by 7. The accumulator starts at `0`. After an `acc` instruction, the instruction immediately below it is executed next.
* `jmp` *jumps* to a new instruction relative to itself. The next instruction to execute is found using the argument as an *offset* from the `jmp` instruction; for example, `jmp +2` would skip the next instruction, `jmp +1` would continue to the instruction immediately below it, and `jmp -20` would cause the instruction 20 lines above to be executed next.
* `nop` stands for *No OPeration* - it does nothing. The instruction immediately below it is executed next.
For example, consider the following program:
```
nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6
```
These instructions are visited in this order:
```
nop +0 | 1
acc +1 | 2, 8(!)
jmp +4 | 3
acc +3 | 6
jmp -3 | 7
acc -99 |
acc +1 | 4
jmp -4 | 5
acc +6 |
```
First, the `nop +0` does nothing. Then, the accumulator is increased from 0 to 1 (`acc +1`) and `jmp +4` sets the next instruction to the other `acc +1` near the bottom. After it increases the accumulator from 1 to 2, `jmp -4` executes, setting the next instruction to the only `acc +3`. It sets the accumulator to 5, and `jmp -3` causes the program to continue back at the first `acc +1`.
This is an *infinite loop*: with this sequence of jumps, the program will run forever. The moment the program tries to run any instruction a second time, you know it will never terminate.
Immediately *before* the program would run an instruction a second time, the value in the accumulator is *`5`*.
Run your copy of the boot code. Immediately before any instruction is executed a second time, *what value is in the accumulator?*
Your puzzle answer was `2080`.
\--- Part Two ---
----------
After some careful analysis, you believe that *exactly one instruction is corrupted*.
Somewhere in the program, *either* a `jmp` is supposed to be a `nop`, *or* a `nop` is supposed to be a `jmp`. (No `acc` instructions were harmed in the corruption of this boot code.)
The program is supposed to terminate by *attempting to execute an instruction immediately after the last instruction in the file*. By changing exactly one `jmp` or `nop`, you can repair the boot code and make it terminate correctly.
For example, consider the same program from above:
```
nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6
```
If you change the first instruction from `nop +0` to `jmp +0`, it would create a single-instruction infinite loop, never leaving that instruction. If you change almost any of the `jmp` instructions, the program will still eventually find another `jmp` instruction and loop forever.
However, if you change the second-to-last instruction (from `jmp -4` to `nop -4`), the program terminates! The instructions are visited in this order:
```
nop +0 | 1
acc +1 | 2
jmp +4 | 3
acc +3 |
jmp -3 |
acc -99 |
acc +1 | 4
nop -4 | 5
acc +6 | 6
```
After the last instruction (`acc +6`), the program terminates by attempting to run the instruction below the last instruction in the file. With this change, after the program terminates, the accumulator contains the value *`8`* (`acc +1`, `acc +1`, `acc +6`).
Fix the program so that it terminates normally by changing exactly one `jmp` (to `nop`) or `nop` (to `jmp`). *What is the value of the accumulator after the program terminates?*
Your puzzle answer was `2477`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, you should [return to your Advent calendar](/2020) and try another puzzle.
If you still want to see it, you can [get your puzzle input](8/input).

Binary file not shown.

View file

@ -0,0 +1,133 @@
use core::fmt::Display;
use std::{num::ParseIntError, collections::HashSet};
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
ParseIntError(std::num::ParseIntError),
LineMalformed(String),
}
impl From<ParseIntError> for ParseError {
fn from(value: ParseIntError) -> Self {
Self::ParseIntError(value)
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ParseIntError(e) => write!(f, "Unable to parse into integer: {e}"),
Self::LineMalformed(v) => write!(f, "Line is malformed: {v}"),
}
}
}
#[derive(Clone)]
enum Instruction {
Acc(isize),
Jmp(isize),
Nop(isize),
}
impl TryFrom<&str> for Instruction {
type Error = ParseError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let parts: Vec<_> = value.split_whitespace().collect();
if parts.len() == 2 {
let argument = if parts[1].starts_with('+') {
parts[1][1..].parse::<isize>()?
} else {
parts[1].parse::<isize>()?
};
match parts[0] {
"acc" => Ok(Self::Acc(argument)),
"jmp" => Ok(Self::Jmp(argument)),
"nop" => Ok(Self::Nop(argument)),
_ => Err(Self::Error::LineMalformed(value.to_string())),
}
} else {
Err(Self::Error::LineMalformed(value.to_string()))
}
}
}
#[derive(Default, Clone)]
struct Cpu {
program: Vec<Instruction>,
next_instr: usize,
accumulator: isize,
visited: HashSet<usize>,
}
impl TryFrom<&str> for Cpu {
type Error = ParseError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let program: Vec<_> = value.lines().map(Instruction::try_from).collect::<Result<Vec<_>, _>>()?;
Ok(Self { program, ..Default::default() })
}
}
impl Cpu {
fn run_until_loop(&mut self) -> Result<isize, isize> {
match self.program[self.next_instr] {
Instruction::Acc(i) => {
self.accumulator += i;
self.next_instr += 1;
},
Instruction::Jmp(p) if p >= 0 => self.next_instr += p.unsigned_abs(),
Instruction::Jmp(n) => self.next_instr -= n.unsigned_abs(),
Instruction::Nop(_) => self.next_instr += 1,
}
if self.visited.contains(&self.next_instr) {
Err(self.accumulator)
} else if self.next_instr == self.program.len() {
Ok(self.accumulator)
} else {
self.visited.insert(self.next_instr);
self.run_until_loop()
}
}
}
pub fn run(input: &str) -> Result<(isize, isize), ParseError> {
let cpu = Cpu::try_from(input)?;
let mut cpu_1 = cpu.clone();
let first = cpu_1.run_until_loop().err().unwrap();
for i in 0..cpu.program.len() {
let new = match cpu.program[i] {
Instruction::Acc(_) => continue,
Instruction::Jmp(i) => Instruction::Nop(i),
Instruction::Nop(i) => Instruction::Jmp(i),
};
let mut cpu_2 = cpu.clone();
cpu_2.program[i] = new;
if let Ok(second) = cpu_2.run_until_loop() {
return Ok((first, second));
}
}
panic!("No way found to break the infinite loop");
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
}
#[test]
fn test_sample() {
let sample_input = read_file("tests/sample_input");
assert_eq!(run(&sample_input), Ok((5, 8)));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), Ok((2080, 2477)));
}
}

View file

@ -0,0 +1,641 @@
acc -8
acc +19
nop +178
jmp +493
acc +7
jmp +267
jmp +604
acc +30
acc +11
acc -17
nop +402
jmp +81
acc +20
acc +19
acc +36
jmp +6
acc +43
acc +6
acc +10
nop +326
jmp +228
nop +371
acc +49
nop +140
acc -11
jmp +3
nop +366
jmp +74
nop +229
jmp +554
acc +12
acc +6
jmp +163
acc +43
acc +23
jmp +310
acc -6
nop +341
acc +50
acc +44
jmp +378
acc +28
acc +29
nop +76
jmp +136
nop +445
acc +27
acc -8
acc +34
jmp +199
acc +39
acc +25
acc -14
acc +1
jmp +189
acc +2
acc -9
jmp -7
acc +28
acc +28
jmp +458
jmp +1
nop +299
jmp +427
acc +10
acc +32
jmp +340
acc +26
jmp +563
jmp +1
acc +9
jmp +42
acc +4
jmp +468
acc +1
acc +3
jmp +258
acc +29
acc +7
acc -5
jmp +288
acc +22
acc +32
acc -6
jmp +173
acc +48
acc +42
acc +26
jmp +380
jmp +126
acc +45
jmp -27
acc +50
jmp +14
jmp +472
acc -19
jmp +363
acc +19
acc -8
acc +25
jmp +450
acc -7
acc +27
acc +44
acc +17
jmp +487
jmp +89
nop +216
nop +345
acc -1
acc +37
jmp +455
jmp +294
acc +20
acc +38
jmp +419
acc +17
acc +17
jmp +125
jmp +81
acc +37
acc -8
acc +9
acc +31
jmp +218
acc +24
acc +28
acc -4
acc -12
jmp -40
acc +40
nop +359
nop +182
nop +306
jmp +296
acc -8
jmp +1
nop +43
acc -14
jmp +239
acc +13
acc +10
jmp +1
jmp -36
acc -16
acc +2
jmp +344
jmp +442
acc +35
acc +2
acc +27
acc +17
jmp -27
nop +478
acc +6
acc +7
jmp +454
nop -145
acc +20
acc -6
jmp +182
nop +251
jmp -37
acc +26
jmp +300
acc +29
acc +44
acc +32
nop +56
jmp +31
acc -16
jmp +53
acc -9
jmp +84
jmp +1
nop +30
acc -15
jmp +262
acc -19
jmp +163
jmp +441
acc +27
jmp +449
acc +42
acc +45
acc +21
acc +22
jmp +338
acc +24
jmp +301
acc +42
acc +42
acc +26
jmp +348
jmp +361
acc -5
acc -19
acc +4
jmp -117
jmp +254
jmp +1
acc +47
acc -3
jmp +271
jmp +388
acc +2
acc -17
acc +37
jmp -73
acc +37
acc +34
jmp +1
jmp -148
jmp -56
jmp +103
acc -5
acc +23
acc +3
jmp +405
nop +255
acc +14
nop -41
acc +12
jmp +94
acc +22
acc +30
jmp -107
acc +12
acc -2
jmp +65
acc +35
acc -4
jmp -174
nop -159
acc +47
jmp -52
acc +35
jmp +73
acc +1
acc +19
acc +35
acc +15
jmp -59
jmp +312
acc +20
acc +25
acc +45
jmp -4
acc -4
nop -160
acc -8
acc +31
jmp +166
acc +20
acc +16
acc -1
jmp +234
acc +0
jmp -45
acc +47
acc +17
nop -187
nop +206
jmp +17
acc +36
acc +0
acc +7
jmp +263
acc +32
acc -6
nop +35
jmp -101
acc +49
nop -60
jmp +118
acc -1
acc -7
nop -94
acc +21
jmp +82
nop +216
acc +5
nop -99
jmp -47
acc +31
acc +2
acc +26
acc +27
jmp -224
acc +15
acc +48
jmp +220
nop +152
jmp -69
acc +4
acc +24
jmp +200
acc +14
jmp +126
acc +48
acc +47
acc +10
jmp +26
acc +16
jmp -203
acc +21
jmp -158
acc -15
acc -13
jmp -94
jmp -136
nop -247
acc +16
jmp -130
acc +31
jmp +115
jmp -159
acc +7
acc +50
jmp +52
acc +22
acc +26
jmp +249
acc -18
jmp +1
jmp -251
nop +254
jmp -127
acc +37
jmp -93
nop +73
acc +11
acc +36
jmp +277
acc +29
acc +16
jmp -88
nop +8
acc +18
acc +47
acc -9
jmp +184
jmp -142
acc +50
jmp +287
jmp -250
jmp -296
jmp -83
acc +13
acc +29
acc +28
acc +16
jmp +40
acc +33
acc -13
jmp +43
nop +275
acc +24
nop -257
nop -65
jmp -112
acc +4
acc +38
jmp -193
jmp +1
acc -18
acc +15
jmp -223
acc -18
jmp -55
jmp -207
acc -6
jmp -215
acc +16
acc +44
jmp +1
acc +47
jmp -35
acc +47
acc +47
acc +35
jmp +144
jmp +1
acc +45
acc +25
jmp -293
acc +32
jmp -381
nop +65
jmp +1
acc +2
jmp -74
acc -13
acc -9
acc +4
jmp -251
jmp +1
jmp +71
acc -12
acc +7
acc +15
jmp +11
jmp -68
acc +33
jmp -330
jmp +48
acc -15
acc -11
jmp +97
acc -9
acc -10
jmp +100
acc +29
acc +21
jmp -134
acc -18
acc +38
jmp +67
jmp -12
acc +27
acc +26
acc -8
acc -2
jmp -124
jmp +165
nop -245
acc -16
acc +25
acc -19
jmp -328
nop -182
acc -7
acc +46
jmp -250
acc +45
acc -7
nop -256
acc -2
jmp +21
acc +21
acc +37
jmp +156
nop +32
jmp -195
nop -355
acc -14
nop -302
acc +48
jmp -407
acc +50
acc -9
acc +47
jmp -110
acc +31
acc +37
acc +15
jmp -162
acc -14
jmp -437
acc +44
jmp +1
acc +24
jmp -139
jmp -362
acc +40
jmp -41
acc +38
jmp -231
acc +31
acc +23
jmp +135
acc -19
acc +15
jmp +148
acc +16
acc -18
acc -3
acc +1
jmp -189
acc -12
acc -6
acc -18
nop -454
jmp +83
nop -190
jmp -17
acc -7
acc +34
acc -1
jmp +94
acc +42
jmp +34
nop -150
nop +90
nop -126
jmp -161
acc +5
acc +11
acc +20
acc +38
jmp -97
acc +49
acc +29
acc +26
jmp -36
acc +4
acc -14
acc +30
acc +42
jmp -192
jmp -336
acc +34
acc +31
acc +2
acc +33
jmp +65
acc +4
jmp -459
nop -399
acc -6
nop -256
jmp -420
acc -12
acc -17
jmp -276
acc +45
acc +40
jmp -180
acc +50
jmp -501
acc +17
jmp -232
acc +12
jmp -109
nop -291
nop -345
jmp +100
acc +36
acc +2
acc -2
jmp +1
acc +23
nop -299
acc +24
acc +30
jmp -476
acc +0
acc +6
acc +49
jmp +6
nop -461
jmp -539
nop -62
acc +48
jmp -526
jmp -365
acc +47
acc +10
acc +32
jmp -490
nop -148
acc +42
acc +5
jmp -358
acc -5
jmp -101
jmp -502
acc +15
acc +45
nop -399
jmp +1
acc +31
acc +47
acc +49
jmp -269
acc +6
acc +45
acc -8
acc -6
jmp +36
jmp +51
acc +39
jmp -64
acc +47
jmp +1
acc -8
jmp -102
acc -8
jmp -202
jmp -18
acc +1
jmp -484
acc +35
acc +30
acc +49
jmp -562
jmp -515
acc -13
nop -6
jmp -369
acc +27
acc +18
nop -477
acc -10
jmp -430
jmp +1
acc +7
nop -111
jmp -445
jmp +12
jmp -50
acc +7
acc +3
nop -433
jmp -390
acc -5
acc +50
jmp -67
acc +45
acc -10
jmp -446
jmp -496
jmp -17
acc +14
acc +33
jmp -239
acc +3
acc -3
acc +27
acc -3
jmp -162
jmp -16
acc +23
acc +26
acc +25
jmp -346
acc +40
acc +45
acc +42
acc -4
jmp +1

View file

@ -0,0 +1,9 @@
nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6