summaryrefslogtreecommitdiff
path: root/d01/src
diff options
context:
space:
mode:
authorPrefetch2023-02-25 11:41:27 +0100
committerPrefetch2023-02-25 11:41:27 +0100
commit3b877bf4cc667eb8bcc787d145203600a4dba2d2 (patch)
treec1d247def29fcb58ae28e4ae4e4d73d1b4e1b27f /d01/src
Initial commit
Diffstat (limited to 'd01/src')
-rw-r--r--d01/src/main.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/d01/src/main.rs b/d01/src/main.rs
new file mode 100644
index 0000000..3117a5a
--- /dev/null
+++ b/d01/src/main.rs
@@ -0,0 +1,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);
+ }
+}