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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
use std::fs;
enum Heading {
North,
East,
South,
West,
}
impl Heading {
fn turn_left(&mut self) {
*self = match *self {
Heading::North => Heading::West,
Heading::East => Heading::North,
Heading::South => Heading::East,
Heading::West => Heading::South,
};
}
fn turn_right(&mut self) {
*self = match *self {
Heading::North => Heading::East,
Heading::East => Heading::South,
Heading::South => Heading::West,
Heading::West => Heading::North,
};
}
}
fn get_route(input: &str) -> Vec<(isize, isize)> {
let steps: Vec<&str> = input.trim().split(", ").collect();
let mut pos = (0, 0);
let mut route = vec![pos];
let mut facing = Heading::North;
for s in steps {
// Read which way to turn
if s.starts_with("L") {
facing.turn_left();
} else if s.starts_with("R") {
facing.turn_right();
}
// Read how far to go in the new direction
let dist: usize = s[1..].parse().unwrap();
// Add each 1-block step to `route' so that part 2 can be solved
for _i in 0..dist {
pos = match facing {
Heading::North => (pos.0 + 1, pos.1),
Heading::East => (pos.0, pos.1 + 1),
Heading::South => (pos.0 - 1, pos.1),
Heading::West => (pos.0, pos.1 - 1),
};
route.push(pos);
}
}
route
}
fn solve_part1(input: &str) -> isize {
let route = get_route(input);
let ended = route.last().unwrap();
// Manhattan distance from origin to `ended' position
ended.0.abs() + ended.1.abs()
}
fn solve_part2(input: &str) -> Option<isize> {
let route = get_route(input);
for i in 1..route.len() {
let pos = route[i - 1];
if route[i..].contains(&pos) {
// Manhattan distance to first twice-visited position
return Some(pos.0.abs() + pos.1.abs());
}
}
None
}
fn main() {
// Read instructions from input text file
let input = fs::read_to_string("input.txt").unwrap();
// Part 1 gives 181 for me
println!("Part 1 solution: {}", solve_part1(&input));
// Part 2 gives 140 for me
println!("Part 2 solution: {}", solve_part2(&input).unwrap());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example1() {
let input = "R2, L3";
assert_eq!(solve_part1(input), 5);
}
#[test]
fn part1_example2() {
let input = "R2, R2, R2";
assert_eq!(solve_part1(input), 2);
}
#[test]
fn part1_example3() {
let input = "R5, L5, R5, R3";
assert_eq!(solve_part1(input), 12);
}
#[test]
fn part2_example1() {
let input = "R8, R4, R4, R8";
assert_eq!(solve_part2(input).unwrap(), 4);
}
}
|