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 }