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 { 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); } }