diff --git a/2019/input_10.txt b/2019/input_10.txt new file mode 100644 index 0000000..bf95472 --- /dev/null +++ b/2019/input_10.txt @@ -0,0 +1,42 @@ +..............#.#...............#....#.... +#.##.......#....#.#..##........#...#...... +..#.....#....#..#.#....#.....#.#.##..#..#. +...........##...#...##....#.#.#....#.##..# +....##....#...........#..#....#......#.### +.#...#......#.#.#.#...#....#.##.##......## +#.##....#.....#.....#...####........###... +.####....#.......#...##..#..#......#...#.. +...............#...........#..#.#.#....... +........#.........##...#..........#..##... +...#..................#....#....##..#..... +.............#..#.#.........#........#.##. +...#.#....................##..##.......... +.....#.#...##..............#...........#.. +......#..###.#........#.....#.##.#......#. +#......#.#.....#...........##.#.....#..#.# +.#.............#..#.....##.....###..#..#.. +.#...#.....#.....##.#......##....##....#.. +.........#.#..##............#..#...#...... +..#..##...#.#..#....#..#.#.......#.##..... +#.......#.#....#.#..##.#...#.......#..###. +.#..........#...##.#....#...#.#.........#. +..#.#.......##..#.##..#.......#.###....... +...#....###...#......#..#.....####........ +.............#.#..........#....#......#... +#................#..................#.###. +..###.........##...##..##................. +.#.........#.#####..#...##....#...##...... +........#.#...#......#.................##. +.##.....#..##.##.#....#....#......#.#....# +.....#...........#.............#.....#.... +........#.##.#...#.###.###....#.#......#.. +..#...#.......###..#...#.##.....###.....#. +....#.....#..#.....#...#......###...###... +#..##.###...##.....#.....#....#...###..#.. +........######.#...............#...#.#...# +...#.....####.##.....##...##.............. +###..#......#...............#......#...#.. +#..#...#.#........#.#.#...#..#....#.#.#### +#..#...#..........##.#.....##........#.#.. +........#....#..###..##....#.#.......##..# +.................##............#.......#.. diff --git a/2019/src/bin/puzzle_10.rs b/2019/src/bin/puzzle_10.rs new file mode 100644 index 0000000..6fc1b33 --- /dev/null +++ b/2019/src/bin/puzzle_10.rs @@ -0,0 +1,117 @@ +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::io; + +use aoc2019::grid::Point; + +#[derive(Ord, PartialOrd, Eq, PartialEq)] +struct AsteroidMetadata { + loc: Point, + distance: u32, +} + +fn gcd(mut a: i32, mut b: i32) -> i32 { + while b != 0 { + let t = b; + b = a % b; + a = t; + } + + a.abs() +} + +fn distances_from( + monitoring_station: Point, + asteroids: &[Point], +) -> HashMap> { + let mut result: HashMap> = HashMap::new(); + + for &a in asteroids { + if a == monitoring_station { + continue; + } + + let delta = a - monitoring_station; + let largest_factor = gcd(delta.x, delta.y); + + result + .entry(Point { + x: delta.x / largest_factor, + y: delta.y / largest_factor, + }) + .or_default() + .push(AsteroidMetadata { + loc: a, + distance: monitoring_station.manhattan_distance(a), + }); + } + + result +} + +fn vaporize_until(asteroids: &HashMap>, count: u32) -> Point { + let mut visible: HashMap<_, _> = asteroids + .iter() + .map(|(k, v)| (k, v.iter().collect::>())) + .collect(); + + let mut vaporization_order: Vec<_> = asteroids.keys().collect(); + + // XXX: Note these are vectors (i.e., (dx, dy)) of the asteroids relative to the monitoring + // station. We reverse the arguments to atan2() from atan2(dy, dx) to atan2(dx, dy) to + // achieve a 90°CCW rotation and a vertical flip of the coordiante system. Sorting by the + // reversed arguments achieves a CCW sweep. To get a CW sweep, we reverse the order. + vaporization_order.sort_by(|a, b| { + f64::from(a.x) + .atan2(f64::from(a.y)) + .total_cmp(&f64::from(b.x).atan2(f64::from(b.y))) + }); + vaporization_order.reverse(); + + let mut result: Point = Default::default(); + let mut i = 0; + let count = usize::try_from(count).unwrap(); + while i < count { + result = match visible + .get_mut(vaporization_order[i % vaporization_order.len()]) + .unwrap() + .pop() + { + Some(a) => a.loc, + None => continue, + }; + i += 1; + } + + result +} + +fn main() { + // XXX: Note that y-coordinate is from the top, and x-coordinate is from the left. + let mut asteroids = vec![]; + for (y, row) in io::stdin().lines().map(|line| line.unwrap()).enumerate() { + for (x, c) in row.chars().enumerate() { + if c == '#' { + asteroids.push(Point { + x: i32::try_from(x).unwrap(), + y: i32::try_from(y).unwrap(), + }); + } + } + } + + let dists_from_station = asteroids + .iter() + .map(|&loc| (loc, distances_from(loc, &asteroids))) + .max_by(|a, b| a.1.len().cmp(&b.1.len())) + .unwrap() + .1; + + println!("Part 1: {}", dists_from_station.len()); + + const BETTED_ASTEROID_VAPORIZED: u32 = 200; + + let asteroid = vaporize_until(&dists_from_station, BETTED_ASTEROID_VAPORIZED); + + println!("Part 2: {}", asteroid.x * 100 + asteroid.y); +} diff --git a/2019/src/grid.rs b/2019/src/grid.rs index 122bb5b..a9e8e48 100644 --- a/2019/src/grid.rs +++ b/2019/src/grid.rs @@ -1,6 +1,7 @@ use std::ops::Add; +use std::ops::Sub; -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +#[derive(Debug, Default, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Point { pub x: i32, pub y: i32, @@ -22,3 +23,14 @@ impl Add for Point { } } } + +impl Sub for Point { + type Output = Self; + + fn sub(self, other: Self) -> Self { + Self { + x: self.x - other.x, + y: self.y - other.y, + } + } +}