Complete day 8 #7

Merged
tlater merged 1 commit from tlater/day-8 into master 2020-12-09 21:16:35 +00:00
6 changed files with 966 additions and 0 deletions

1
day-8/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target/

106
day-8/Cargo.lock generated Normal file
View file

@ -0,0 +1,106 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "day-8"
version = "0.1.0"
dependencies = [
"indoc",
"snafu",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "indoc"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
dependencies = [
"indoc-impl",
"proc-macro-hack",
]
[[package]]
name = "indoc-impl"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"unindent",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
[[package]]
name = "snafu"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7"
dependencies = [
"doc-comment",
"snafu-derive",
]
[[package]]
name = "snafu-derive"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"

11
day-8/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "day-8"
version = "0.1.0"
authors = ["Tristan Daniël Maat <tm@tlater.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
indoc = "0.3"
snafu = "0.6"

612
day-8/input Normal file
View file

@ -0,0 +1,612 @@
jmp +236
acc +43
acc +28
jmp +149
acc +28
acc +13
acc +36
acc +42
jmp +439
acc -14
jmp +29
jmp +154
acc +16
acc -13
acc -16
nop +317
jmp +497
acc +21
jmp +386
jmp +373
acc +22
jmp +311
acc -16
acc +27
acc +21
acc +43
jmp +512
jmp +218
jmp +217
acc +12
acc +44
nop +367
nop +180
jmp +134
acc -2
acc +42
acc +13
acc -11
jmp +442
nop +457
jmp +151
acc +15
acc -4
acc +0
jmp +131
acc +6
acc -2
acc +37
jmp +112
acc +32
acc +6
acc -15
jmp +474
jmp +515
acc +12
acc +11
acc +4
jmp +339
acc -3
acc +36
jmp +220
nop +91
acc -12
jmp +49
acc -17
jmp +204
acc +40
jmp +535
acc +37
acc +8
nop +147
nop +174
jmp +306
jmp +305
acc +7
acc +33
jmp +305
acc +22
acc +17
acc +24
jmp +458
jmp +1
acc +36
acc +34
jmp +113
acc -3
nop +113
nop -34
jmp +506
acc -19
acc +21
acc +35
acc -1
jmp +74
acc +15
acc +7
jmp +79
acc +29
acc +42
jmp +427
acc +33
jmp +29
acc +6
acc +13
nop +477
acc +26
jmp +493
acc +33
acc +43
acc +49
acc +35
jmp +409
acc -7
acc +35
acc +40
jmp +309
acc -13
acc -14
acc +32
jmp +322
jmp +10
jmp +44
acc +20
acc +25
jmp +175
acc +22
acc +16
acc +1
acc +36
jmp -65
jmp +231
acc +35
jmp +155
jmp +218
acc -10
acc -13
acc +38
jmp -92
acc +15
jmp +134
acc -16
acc +18
jmp -30
nop -41
acc +48
acc +49
jmp -107
acc +4
acc +34
acc +38
acc -18
jmp +247
acc +45
acc +23
jmp +149
nop +164
acc +26
jmp -24
jmp +240
jmp +77
acc +30
acc -13
jmp -158
nop +136
jmp +33
jmp +189
jmp +143
jmp +1
acc +4
acc +30
jmp -106
acc +16
nop -52
acc +37
jmp +119
acc -11
acc -9
acc +15
acc +4
jmp +301
jmp +1
acc -3
jmp +188
nop +86
nop +125
acc -10
jmp -105
acc +36
acc +9
acc +0
jmp +317
jmp +347
acc +48
nop +380
acc -18
acc +28
jmp +398
jmp -152
jmp -86
acc +22
acc +11
acc +39
jmp -173
jmp +343
nop +194
nop +98
nop +382
jmp +300
acc +35
nop +287
acc -8
jmp +302
acc +19
acc +45
jmp +95
acc +29
jmp +274
acc +18
acc -13
acc +23
acc +7
jmp +164
acc +17
acc +36
acc -5
jmp +153
acc +21
jmp +105
jmp +1
nop +267
jmp +277
jmp +88
acc +2
acc +18
nop +182
jmp +189
acc +37
acc +46
jmp +258
acc +22
acc +15
jmp +249
acc +17
jmp -162
jmp +25
acc -6
nop +314
jmp -30
jmp +312
acc +34
nop -230
acc -2
jmp +158
acc -4
acc +37
jmp +318
acc +18
acc +23
acc -8
jmp -248
jmp +181
acc +17
acc +4
jmp -189
acc +27
acc -13
acc -4
acc +8
jmp +222
jmp +310
acc -5
acc +35
jmp +241
jmp -130
jmp +124
acc -19
jmp +331
acc -8
acc +45
jmp +106
acc +23
acc +48
jmp -107
acc +7
acc -19
acc +3
jmp +130
jmp -104
nop +5
acc +29
acc +8
acc -6
jmp +7
acc +12
jmp +102
acc -4
acc +46
acc -17
jmp -209
acc +20
jmp -271
acc +48
jmp +30
nop +204
acc -19
acc +4
acc +38
jmp +17
jmp +116
acc -17
acc +23
jmp -75
jmp -129
jmp +152
acc +36
nop -193
acc +26
acc +38
jmp +242
jmp -197
acc +32
acc -5
acc -19
jmp -201
jmp -304
acc +9
jmp +175
acc +1
jmp -15
jmp +1
nop -74
jmp -38
nop -165
acc -19
jmp -317
acc -19
acc -1
jmp +17
acc +0
nop +151
jmp +93
acc +32
acc +29
acc +0
jmp -340
acc +39
jmp -115
acc +0
acc +47
nop -320
jmp +244
acc +29
jmp +81
jmp -84
acc +2
acc +16
nop -345
acc +23
jmp +9
acc +26
jmp -67
acc -11
acc +38
jmp +150
acc +19
acc -2
jmp -244
jmp +88
acc -4
jmp -157
acc +22
acc +33
acc +41
jmp -117
acc +31
acc +50
acc +24
jmp -265
jmp +1
jmp -352
jmp -312
acc +35
acc +30
jmp -90
jmp +8
acc +14
acc +39
jmp -112
acc -11
acc -3
acc +22
jmp -116
acc +48
jmp -194
acc -5
jmp -252
jmp +66
jmp -295
jmp +196
acc +25
acc -11
nop +112
acc +33
jmp +123
acc -10
acc +28
nop -119
acc +12
jmp -166
jmp -356
acc +8
acc +16
jmp +161
acc +25
acc +3
jmp -5
acc +32
acc +40
jmp +181
acc -11
acc -5
jmp +1
acc +0
jmp -265
acc +5
acc +24
acc +15
acc -17
jmp -326
nop +103
acc -9
acc +13
jmp -379
acc +38
acc +16
jmp -65
jmp +1
jmp +1
jmp +1
acc -1
jmp -191
acc +35
acc -19
acc -6
jmp -52
acc +15
jmp -357
nop -134
acc -3
nop +103
jmp -123
acc +43
acc +0
acc +47
jmp -373
acc +0
acc +50
acc +44
acc +21
jmp -114
acc -19
jmp -339
acc +25
jmp -410
jmp -126
acc -2
acc -6
acc +14
jmp -207
acc +35
acc -7
jmp +75
acc +9
acc +22
jmp +114
acc +18
acc +36
acc +0
acc +40
jmp -192
acc +35
acc +0
acc +28
acc +3
jmp -346
nop -131
acc +46
nop -467
nop -179
jmp -151
jmp -120
acc +30
acc +22
acc -7
acc +18
jmp -157
acc +5
jmp +76
nop -315
acc +25
jmp -357
acc +44
jmp -12
acc +0
acc +19
nop -485
jmp -495
nop -115
acc +12
jmp -8
acc +31
acc -7
jmp -158
acc +44
acc +32
jmp +87
acc +1
acc +37
acc +44
jmp -86
acc +0
acc +17
acc -13
jmp -434
acc +37
jmp -342
acc +3
jmp +1
acc +29
jmp -242
acc +48
jmp -442
jmp -283
acc -19
acc +6
acc +20
acc +44
jmp -533
acc -15
nop -356
acc +18
jmp -408
acc -9
acc +17
acc +16
jmp -385
nop -130
jmp +1
acc +38
acc +39
jmp -324
jmp -141
acc +4
acc +3
acc -4
jmp -114
acc +2
jmp +1
acc +44
jmp -360
acc +43
acc +36
nop -177
nop -288
jmp -496
acc +45
acc +0
jmp -322
acc +13
jmp -511
acc -2
acc +36
jmp -460
acc +28
acc +28
jmp -455
acc -4
acc +38
jmp -145
jmp -163
jmp -331
nop -227
jmp -470
acc +35
nop -419
acc +39
acc +0
jmp -435
jmp +1
jmp -69
acc +20
acc +46
nop +2
jmp -239
acc -3
acc +12
acc +38
jmp -259
jmp -60
jmp -67
nop -542
jmp -397
acc +32
jmp -57
acc +30
nop -393
jmp -380
acc +16
acc -7
acc +0
acc +2
jmp +1

187
day-8/src/emulator.rs Normal file
View file

@ -0,0 +1,187 @@
use std::collections::HashSet;
use snafu::Snafu;
pub type Program = Vec<(Instruction, i64)>;
#[derive(Debug, PartialEq, Snafu)]
pub enum EmulatorError {
#[snafu(display("Segmentation fault"))]
SegmentationFault,
#[snafu(display("Infinite loop: {}", accumulator))]
InfiniteLoop { accumulator: i64 },
}
#[derive(Debug, Snafu)]
pub enum ProgramParseError {
#[snafu(display("Invalid instruction given: {}", instruction))]
InvalidInstruction { instruction: String },
#[snafu(display("Invalid argument given: {}", argument))]
InvalidArgument { argument: String },
#[snafu(display("Unparseable line: {}", line))]
InvalidLine { line: String },
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Instruction {
Accumulate,
Jump,
NoOperation,
}
pub struct Emulator {
accumulator: i64,
program_counter: usize,
}
impl Emulator {
pub fn new() -> Self {
Self {
accumulator: 0,
program_counter: 0,
}
}
pub fn reset(&mut self) {
self.accumulator = 0;
self.program_counter = 0;
}
fn execute_instruction(
&mut self,
instruction: Instruction,
argument: i64,
) -> Result<(), EmulatorError> {
match instruction {
Instruction::Accumulate => self.accumulator += argument,
Instruction::Jump => {
self.program_counter = self.program_counter.wrapping_add(argument as usize - 1)
}
Instruction::NoOperation => {}
}
Ok(())
}
pub fn run_program_finitely(&mut self, program: &Program) -> Result<i64, EmulatorError> {
let mut executed = HashSet::new();
loop {
let (instruction, argument) = program
.get(self.program_counter)
.ok_or(EmulatorError::SegmentationFault)?;
executed.insert(self.program_counter);
self.execute_instruction(*instruction, *argument)?;
self.program_counter += 1;
if executed.contains(&self.program_counter) {
break Err(EmulatorError::InfiniteLoop {
accumulator: self.accumulator,
});
} else if self.program_counter >= program.len() {
break Ok(self.accumulator);
}
}
}
}
pub fn parse_code(input: &str) -> Result<Program, ProgramParseError> {
input
.lines()
.map(|instruction| {
let (name, argument): (&str, &str) = {
let temp: Vec<&str> = instruction.split(' ').collect();
if temp.len() != 2 {
Err(ProgramParseError::InvalidLine {
line: instruction.to_string(),
})
} else {
Ok((temp[0], temp[1]))
}
}?;
Ok((
match name {
"acc" => Instruction::Accumulate,
"jmp" => Instruction::Jump,
"nop" => Instruction::NoOperation,
_ => Err(ProgramParseError::InvalidInstruction {
instruction: name.to_string(),
})?,
},
argument
.parse()
.or(Err(ProgramParseError::InvalidArgument {
argument: argument.to_string(),
}))?,
))
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
#[test]
fn test_parsing() -> Result<(), Box<dyn std::error::Error>> {
let input = indoc!(
"nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6
"
);
let code = parse_code(&input)?;
assert_eq!(
code,
vec![
(Instruction::NoOperation, 0),
(Instruction::Accumulate, 1),
(Instruction::Jump, 4),
(Instruction::Accumulate, 3),
(Instruction::Jump, -3),
(Instruction::Accumulate, -99),
(Instruction::Accumulate, 1),
(Instruction::Jump, -4),
(Instruction::Accumulate, 6),
]
);
Ok(())
}
#[test]
fn test_running() -> Result<(), Box<dyn std::error::Error>> {
let input = indoc!(
"nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6
"
);
let code = parse_code(&input)?;
let mut emulator = Emulator::new();
assert_eq!(
emulator.run_program_finitely(&code),
Err(EmulatorError::InfiniteLoop { accumulator: 5 })
);
Ok(())
}
}

49
day-8/src/main.rs Normal file
View file

@ -0,0 +1,49 @@
use std::fs;
mod emulator;
use emulator::{parse_code, Emulator, EmulatorError, Instruction};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = fs::read_to_string("input")?;
let program = parse_code(&input)?;
// Part 1
let mut emulator = Emulator::new();
if let Err(EmulatorError::InfiniteLoop { accumulator }) =
emulator.run_program_finitely(&program)
{
println!("{}", accumulator);
} else {
panic!("We should get an infinite loop.");
}
// Part 2
let result = program
.iter()
.enumerate()
.filter_map(|(i, instruction)| match instruction {
(Instruction::Jump, arg) => {
let mut program = program.clone();
program[i] = (Instruction::NoOperation, *arg);
emulator.reset();
emulator.run_program_finitely(&program).ok()
}
(Instruction::NoOperation, arg) => {
let mut program = program.clone();
program[i] = (Instruction::Jump, *arg);
emulator.reset();
emulator.run_program_finitely(&program).ok()
}
(_, _) => None,
})
.next();
if let Some(result) = result {
println!("{}", result);
} else {
panic!("We should have at least one non-infinte loop.");
}
Ok(())
}