-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path08_up.rs
93 lines (84 loc) · 2.4 KB
/
08_up.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use std::collections::HashSet;
use std::fs;
use std::str::FromStr;
/// An intcode command.
#[derive(Debug)]
enum Cmd {
Nop(isize),
Acc(isize),
Jmp(isize),
}
impl FromStr for Cmd {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let cmd_name = &s[..3];
let x = s[4..].parse().unwrap();
let cmd = match cmd_name {
"nop" => Cmd::Nop(x),
"acc" => Cmd::Acc(x),
"jmp" => Cmd::Jmp(x),
_ => panic!("Unknown command: {}", cmd_name),
};
Ok(cmd)
}
}
/// Run intcodes.
///
/// # Arguments
/// * `cmd` -- A sequence of intcode commands
///
/// # Returns
/// * `acc` -- The value of the accumulator
/// * `looped` -- Boolean, true if the program ended in an infinite loop
/// * `seen` -- Indices of commands that were executed.
fn run(cmd: &[Cmd]) -> (isize, bool, HashSet<isize>) {
let mut acc: isize = 0;
let mut ptr: isize = 0;
let mut seen: HashSet<isize> = HashSet::new();
let mut looped = false;
while ptr < cmd.len() as isize {
if seen.contains(&ptr) {
looped = true;
break;
}
seen.insert(ptr);
match cmd[ptr as usize] {
Cmd::Nop(_) => (),
Cmd::Acc(x) => acc += x,
Cmd::Jmp(x) => ptr += x - 1,
}
ptr += 1;
}
(acc, looped, seen)
}
#[doc(hidden)]
fn main() {
// Read input
let mut cmd: Vec<Cmd> = fs::read_to_string("input/08.txt")
.expect("Can't read input file.")
.trim()
.lines()
.map(|s| s.parse::<Cmd>().expect("Can't parse command"))
.collect();
// Part 1
let (acc, _looped, seen) = run(&cmd);
println!("Part 1: {}", acc);
// Part 2
// One of the "jmp" commands that were exectued in part 1 has to
// be replaced by a "nop" command (or vice versa, which, however,
// is not the case). Brute-force the solution by trying to replace
// each of the "jmp" commands in `seen` by `nop` until the code
// doesn't loop.
for ptr in seen {
if let Cmd::Jmp(x) = cmd[ptr as usize] {
cmd[ptr as usize] = Cmd::Nop(x);
let (acc, looped, _seen) = run(&cmd);
if !looped {
println!("Part 2: {}", acc);
break;
}
// Restore the original "jmp" command.
cmd[ptr as usize] = Cmd::Jmp(x);
}
}
}