Browse Source

Completed day 3

Tyler Hallada 4 years ago
parent
commit
3b06ca1c64
7 changed files with 223 additions and 0 deletions
  1. 6 0
      day3/Cargo.lock
  2. 9 0
      day3/Cargo.toml
  3. 2 0
      day3/input/input.txt
  4. 2 0
      day3/input/test1.txt
  5. 2 0
      day3/input/test2.txt
  6. 2 0
      day3/input/test3.txt
  7. 200 0
      day3/src/main.rs

+ 6 - 0
day3/Cargo.lock

@@ -0,0 +1,6 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+[[package]]
4
+name = "day3"
5
+version = "0.1.0"
6
+

+ 9 - 0
day3/Cargo.toml

@@ -0,0 +1,9 @@
1
+[package]
2
+name = "day3"
3
+version = "0.1.0"
4
+authors = ["Tyler Hallada <tyler@hallada.net>"]
5
+edition = "2018"
6
+
7
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
+
9
+[dependencies]

File diff suppressed because it is too large
+ 2 - 0
day3/input/input.txt


+ 2 - 0
day3/input/test1.txt

@@ -0,0 +1,2 @@
1
+R8,U5,L5,D3
2
+U7,R6,D4,L4

+ 2 - 0
day3/input/test2.txt

@@ -0,0 +1,2 @@
1
+R75,D30,R83,U83,L12,D49,R71,U7,L72
2
+U62,R66,U55,R34,D71,R55,D58,R83

+ 2 - 0
day3/input/test3.txt

@@ -0,0 +1,2 @@
1
+R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
2
+U98,R91,D20,R16,D67,R40,U7,R15,U6,R7

+ 200 - 0
day3/src/main.rs

@@ -0,0 +1,200 @@
1
+use std::collections::HashMap;
2
+use std::error::Error;
3
+use std::fs;
4
+use std::result;
5
+use std::str::FromStr;
6
+
7
+const INPUT: &str = "input/input.txt";
8
+
9
+type Result<T> = result::Result<T, Box<dyn Error>>;
10
+
11
+#[derive(Debug, PartialEq)]
12
+struct CrossedWires {
13
+    wires: Vec<Vec<Move>>,
14
+}
15
+
16
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17
+struct Point {
18
+    x: i32,
19
+    y: i32,
20
+}
21
+
22
+#[derive(Debug, PartialEq)]
23
+struct Move {
24
+    direction: Direction,
25
+    distance: i32,
26
+}
27
+
28
+#[derive(Debug, PartialEq)]
29
+enum Direction {
30
+    Up,
31
+    Down,
32
+    Right,
33
+    Left,
34
+}
35
+
36
+impl CrossedWires {
37
+    fn find_intersections(&self) -> HashMap<Point, u32> {
38
+        let mut intersections: HashMap<Point, u32> = HashMap::new();
39
+
40
+        let mut occupied_points: HashMap<Point, u32> = HashMap::new();
41
+        for (wire_index, wire) in self.wires.iter().enumerate() {
42
+            let mut steps = 0;
43
+            let mut end_point = Point { x: 0, y: 0 };
44
+            for movement in wire.iter() {
45
+                let mut point = end_point.clone();
46
+                for _ in 0..movement.distance {
47
+                    match movement.direction {
48
+                        Direction::Up => point.y += 1,
49
+                        Direction::Down => point.y -= 1,
50
+                        Direction::Right => point.x += 1,
51
+                        Direction::Left => point.x -= 1,
52
+                    };
53
+                    steps += 1;
54
+                    if wire_index == 0 {
55
+                        occupied_points.insert(point, steps);
56
+                    } else {
57
+                        if let Some(first_wire_steps) = occupied_points.get(&point) {
58
+                            intersections.insert(point, first_wire_steps + steps);
59
+                        }
60
+                    }
61
+                }
62
+                end_point = point;
63
+            }
64
+        }
65
+
66
+        intersections
67
+    }
68
+}
69
+
70
+impl FromStr for CrossedWires {
71
+    type Err = Box<dyn Error>;
72
+
73
+    fn from_str(s: &str) -> Result<CrossedWires> {
74
+        let mut wires = s.split("\n");
75
+        let first_moves = wires.next().expect("First wire not found in input");
76
+        let second_moves = wires.next().expect("Second wire not found in input");
77
+
78
+        Ok(CrossedWires {
79
+            wires: vec![
80
+                get_moves_from_string(first_moves)?,
81
+                get_moves_from_string(second_moves)?,
82
+            ],
83
+        })
84
+    }
85
+}
86
+
87
+impl From<char> for Direction {
88
+    fn from(c: char) -> Direction {
89
+        match c {
90
+            'U' => Direction::Up,
91
+            'D' => Direction::Down,
92
+            'R' => Direction::Right,
93
+            'L' => Direction::Left,
94
+            _ => panic!("Could not parse direction: {}", c),
95
+        }
96
+    }
97
+}
98
+
99
+fn get_moves_from_string(moves_string: &str) -> Result<Vec<Move>> {
100
+    let moves_strings = moves_string.split(",");
101
+    let mut moves = vec![];
102
+
103
+    for wire_move in moves_strings {
104
+        let mut wire_move = wire_move.chars();
105
+        let direction: Direction =
106
+            Direction::from(wire_move.next().expect("Invalid empty wire move"));
107
+        let distance: i32 = wire_move.collect::<String>().parse()?;
108
+
109
+        moves.push(Move {
110
+            direction,
111
+            distance,
112
+        });
113
+    }
114
+    Ok(moves)
115
+}
116
+
117
+fn read_wires(filename: &str) -> Result<CrossedWires> {
118
+    let wires = fs::read_to_string(filename)?;
119
+    Ok(wires.parse()?)
120
+}
121
+
122
+fn solve_part1() -> Result<i32> {
123
+    let wires = read_wires(INPUT)?;
124
+    let intersections = wires.find_intersections();
125
+    let intersect_points = intersections.keys();
126
+    let distances = intersect_points.map(|point| point.x.abs() + point.y.abs());
127
+    Ok(distances.min().expect("No intersections found"))
128
+}
129
+
130
+fn solve_part2() -> Result<i32> {
131
+    let wires = read_wires(INPUT)?;
132
+    let intersections = wires.find_intersections();
133
+    let min_intersection = intersections
134
+        .iter()
135
+        .min_by_key(|(_, steps)| steps.clone()).expect("No intersections found");
136
+    Ok(*min_intersection.1 as i32)
137
+}
138
+
139
+fn main() -> Result<()> {
140
+    println!("Part 1: {}", solve_part1()?);
141
+    println!("Part 2: {}", solve_part2()?);
142
+
143
+    Ok(())
144
+}
145
+
146
+#[cfg(test)]
147
+mod tests {
148
+    use super::*;
149
+
150
+    const TEST_INPUT1: &str = "input/test1.txt";
151
+    // const TEST_INPUT2: &str = "input/test2.txt";
152
+    // const TEST_INPUT3: &str = "input/test3.txt";
153
+
154
+    #[test]
155
+    fn reads_wires() {
156
+        assert_eq!(
157
+            read_wires(TEST_INPUT1).unwrap(),
158
+            CrossedWires {
159
+                wires: vec![
160
+                    vec![
161
+                        Move {
162
+                            direction: Direction::Right,
163
+                            distance: 8
164
+                        },
165
+                        Move {
166
+                            direction: Direction::Up,
167
+                            distance: 5
168
+                        },
169
+                        Move {
170
+                            direction: Direction::Left,
171
+                            distance: 5
172
+                        },
173
+                        Move {
174
+                            direction: Direction::Down,
175
+                            distance: 3
176
+                        },
177
+                    ],
178
+                    vec![
179
+                        Move {
180
+                            direction: Direction::Up,
181
+                            distance: 7
182
+                        },
183
+                        Move {
184
+                            direction: Direction::Right,
185
+                            distance: 6
186
+                        },
187
+                        Move {
188
+                            direction: Direction::Down,
189
+                            distance: 4
190
+                        },
191
+                        Move {
192
+                            direction: Direction::Left,
193
+                            distance: 4
194
+                        },
195
+                    ],
196
+                ],
197
+            }
198
+        );
199
+    }
200
+}