Browse Source

Work in progress day 10 part 2

Tyler Hallada 4 years ago
parent
commit
e007f0b3f9
1 changed files with 101 additions and 37 deletions
  1. 101 37
      day10/src/main.rs

+ 101 - 37
day10/src/main.rs

@@ -1,7 +1,9 @@
1
-use std::collections::HashMap;
1
+use std::cmp::Ordering;
2
+use std::collections::{HashMap, VecDeque};
2 3
 use std::error::Error;
3 4
 use std::fs::File;
4 5
 use std::io::{prelude::*, BufReader};
6
+use std::iter::FromIterator;
5 7
 use std::result;
6 8
 
7 9
 use num::integer::gcd;
@@ -22,47 +24,65 @@ struct AsteroidField {
22 24
 }
23 25
 
24 26
 impl AsteroidField {
25
-    fn find_monitoring_station(&self) -> (&Point, usize) {
26
-        let mut asteroid_detect_scores = HashMap::new();
27
+    fn get_lines_of_sight(&self, from_point: &Point) -> HashMap<(i32, i32), VecDeque<&Point>> {
28
+        let mut lines_of_sight: HashMap<(i32, i32), VecDeque<&Point>> = HashMap::new();
27 29
         for asteroid in self.asteroids.iter() {
28
-            let mut lines_of_sight: HashMap<(i32, i32), Point> = HashMap::new();
29
-            for other in self.asteroids.iter() {
30
-                if asteroid != other {
31
-                    let x_dist: i32 = other.x as i32 - asteroid.x as i32;
32
-                    let y_dist: i32 = other.y as i32 - asteroid.y as i32;
33
-                    let mut x_ratio: i32 = 0;
34
-                    let mut y_ratio: i32 = 0;
35
-                    if x_dist == 0 {
36
-                        if y_dist > 0 {
37
-                            y_ratio = 1;
38
-                        } else {
39
-                            y_ratio = -1;
40
-                        }
41
-                    } else if y_dist == 0 {
42
-                        if x_dist > 0 {
43
-                            x_ratio = 1;
44
-                        } else {
45
-                            x_ratio = -1;
46
-                        }
30
+            if from_point != asteroid {
31
+                let x_dist: i32 = asteroid.x as i32 - from_point.x as i32;
32
+                let y_dist: i32 = asteroid.y as i32 - from_point.y as i32;
33
+                let mut x_ratio: i32 = 0;
34
+                let mut y_ratio: i32 = 0;
35
+                if x_dist == 0 {
36
+                    if y_dist > 0 {
37
+                        y_ratio = 1;
38
+                    } else {
39
+                        y_ratio = -1;
40
+                    }
41
+                } else if y_dist == 0 {
42
+                    if x_dist > 0 {
43
+                        x_ratio = 1;
47 44
                     } else {
48
-                        let gcd = gcd(x_dist, y_dist);
49
-                        x_ratio = x_dist / gcd;
50
-                        y_ratio = y_dist / gcd;
45
+                        x_ratio = -1;
51 46
                     }
52
-                    lines_of_sight
53
-                        .entry((x_ratio, y_ratio))
54
-                        .and_modify(|current| {
55
-                            if (current.x as i32 - asteroid.x as i32).abs() > x_dist.abs()
56
-                                && (current.y as i32 - asteroid.y as i32).abs() > y_dist.abs()
47
+                } else {
48
+                    let gcd = gcd(x_dist, y_dist);
49
+                    x_ratio = x_dist / gcd;
50
+                    y_ratio = y_dist / gcd;
51
+                }
52
+
53
+                lines_of_sight
54
+                    .entry((x_ratio, y_ratio))
55
+                    .and_modify(|deque| {
56
+                        let mut insertion_index = None;
57
+                        for (index, current) in deque.iter().enumerate() {
58
+                            if (current.x as i32 - from_point.x as i32).abs() > x_dist.abs()
59
+                                && (current.y as i32 - from_point.y as i32).abs() > y_dist.abs()
57 60
                             {
58
-                                current.x = other.x;
59
-                                current.y = other.y;
61
+                                insertion_index = Some(index);
62
+                                break;
60 63
                             }
61
-                        })
62
-                        .or_insert(other.clone());
63
-                }
64
+                        }
65
+                        if let Some(index) = insertion_index {
66
+                            deque.insert(index, asteroid);
67
+                        } else {
68
+                            deque.push_back(asteroid);
69
+                        }
70
+                    })
71
+                    .or_insert_with(|| {
72
+                        let mut deque = VecDeque::new();
73
+                        deque.push_back(asteroid);
74
+                        deque
75
+                    });
64 76
             }
77
+        }
78
+        lines_of_sight
79
+    }
65 80
 
81
+    fn find_monitoring_station(&self) -> (&Point, usize) {
82
+        let mut asteroid_detect_scores = HashMap::new();
83
+
84
+        for asteroid in self.asteroids.iter() {
85
+            let lines_of_sight = self.get_lines_of_sight(asteroid);
66 86
             asteroid_detect_scores.insert(asteroid, lines_of_sight.len());
67 87
         }
68 88
 
@@ -71,6 +91,48 @@ impl AsteroidField {
71 91
             .max_by_key(|score| score.1)
72 92
             .expect("No asteroid detect scores")
73 93
     }
94
+
95
+    fn vaporize_asteroids(&mut self, laser_point: &Point) -> Option<&Point> {
96
+        let mut vaporized_counter = 0;
97
+        let mut lines_of_sight = self.get_lines_of_sight(laser_point);
98
+        let mut directions: Vec<(i32, i32)> = lines_of_sight.keys().map(|key| *key).collect();
99
+        directions.sort_by(|a, b| {
100
+            let det = a.0 * b.1 - b.0 * a.1;
101
+            if det > 0 {
102
+                Ordering::Less
103
+            } else if det < 0 {
104
+                Ordering::Greater
105
+            } else {
106
+                Ordering::Equal
107
+            }
108
+        });
109
+        let up = directions
110
+            .iter()
111
+            .position(|&dir| dir == (0, -1))
112
+            .expect("No asteroid directly up from laser");
113
+        directions.rotate_left(up);
114
+        dbg!(&directions);
115
+
116
+        for direction in directions.iter() {
117
+            // dbg!(direction);
118
+            let in_sight = lines_of_sight.get_mut(direction);
119
+            if let Some(in_sight) = in_sight {
120
+                // dbg!(&in_sight);
121
+                if let Some(vaporized_asteroid) = in_sight.pop_back() {
122
+                    vaporized_counter += 1;
123
+
124
+                    // dbg!(&vaporized_counter);
125
+                    // dbg!(&vaporized_asteroid);
126
+
127
+                    if vaporized_counter == 200 {
128
+                        return Some(vaporized_asteroid);
129
+                    }
130
+                }
131
+            }
132
+        }
133
+
134
+        None
135
+    }
74 136
 }
75 137
 
76 138
 fn read_asteroid_field(filename: &str) -> Result<AsteroidField> {
@@ -94,8 +156,10 @@ fn solve_part1() -> Result<usize> {
94 156
     Ok(asteroid_field.find_monitoring_station().1)
95 157
 }
96 158
 
97
-fn solve_part2() -> Result<i64> {
98
-    Ok(1)
159
+fn solve_part2() -> Result<usize> {
160
+    let mut asteroid_field = read_asteroid_field("input/test5.txt")?;
161
+    let vaporized200 = asteroid_field.vaporize_asteroids(&Point { x: 11, y: 13 }).unwrap();
162
+    Ok(vaporized200.x * 100 + vaporized200.y)
99 163
 }
100 164
 
101 165
 fn main() -> Result<()> {