main.rs (2189B)
1 use std::cmp::Ordering; 2 use std::collections::HashSet; 3 4 #[derive(Debug)] 5 enum Dir { 6 Left, 7 Right, 8 Up, 9 Down, 10 } 11 12 impl Dir { 13 fn from_str(s: &str) -> Self { 14 match s { 15 "L" => Self::Left, 16 "R" => Self::Right, 17 "U" => Self::Up, 18 "D" => Self::Down, 19 _ => unreachable!(), 20 } 21 } 22 } 23 24 fn sign(x: i32) -> i32 { 25 match x.cmp(&0) { 26 Ordering::Greater => 1, 27 Ordering::Equal => 0, 28 Ordering::Less => -1, 29 } 30 } 31 32 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 33 struct Coord(i32, i32); 34 35 impl Coord { 36 fn move_in(&mut self, dir: &Dir) { 37 match dir { 38 Dir::Left => self.0 = self.0 - 1, 39 Dir::Right => self.0 = self.0 + 1, 40 Dir::Up => self.1 = self.1 + 1, 41 Dir::Down => self.1 = self.1 - 1, 42 } 43 } 44 45 fn is_touching(&self, other: &Coord) -> bool { 46 return (other.0 - self.0).abs() <= 1 && (other.1 - self.1).abs() <= 1; 47 } 48 49 fn follow(&mut self, other: &Coord) { 50 self.0 = self.0 + sign(other.0 - self.0); 51 self.1 = self.1 + sign(other.1 - self.1); 52 } 53 } 54 55 fn main() { 56 let input = std::fs::read_to_string("input.txt") 57 .unwrap() 58 .trim() 59 .split("\n") 60 .map(|x| { 61 let tmp = x.split(' ').collect::<Vec<_>>(); 62 (Dir::from_str(tmp[0]), tmp[1].parse::<i32>().unwrap()) 63 }) 64 .collect::<Vec<(Dir, i32)>>(); 65 // 6087 66 println!("Part 1: {}", part_1(&input, 2)); 67 // 2493 68 println!("Part 2: {}", part_1(&input, 10)); 69 } 70 71 fn part_1(input: &Vec<(Dir, i32)>, rope_length: usize) -> usize { 72 let mut rope = vec![Coord(0, 0); rope_length]; 73 let mut visited = HashSet::new(); 74 visited.insert(rope.last().unwrap().clone()); 75 for (dir, step) in input { 76 for _ in 0..*step { 77 rope[0].move_in(dir); 78 for i in 1..rope_length { 79 if !rope[i].is_touching(&rope[i - 1]) { 80 let tmp = rope[i - 1].clone(); 81 rope[i].follow(&tmp); 82 } 83 } 84 visited.insert(rope.last().unwrap().clone()); 85 } 86 } 87 visited.len() 88 }