diff --git a/2019/day10_monitoring_station/src/lib.rs b/2019/day10_monitoring_station/src/lib.rs index d6c69a4..bba6dcd 100644 --- a/2019/day10_monitoring_station/src/lib.rs +++ b/2019/day10_monitoring_station/src/lib.rs @@ -3,19 +3,25 @@ use std::collections::BTreeSet; #[derive(PartialEq, Eq)] struct RationalAngle { - upper_half: bool, + quadrant: u8, divident: isize, - divisor: usize, + divisor: isize, } impl From<(isize, isize)> for RationalAngle { fn from((x, y): (isize, isize)) -> Self { - let upper_half = x < 0; - let divident = y.signum() * x / gcd(x, y); - let divisor = (y / gcd(x, y)).unsigned_abs(); + let quadrant = match (x.signum(), y.signum()) { + (0, -1) | (1, -1) => 1, + (1, 0) | (1, 1) => 2, + (0, 1) | (-1, 1) => 3, + (-1, 0) | (-1, -1) => 4, + _ => panic!("Unexpected combination of signs: {x}, {y}"), + }; + let divident = x / gcd(x, y); + let divisor = y / gcd(x, y); Self { - upper_half, + quadrant, divident, divisor, } @@ -24,14 +30,9 @@ impl From<(isize, isize)> for RationalAngle { impl PartialOrd for RationalAngle { fn partial_cmp(&self, other: &Self) -> Option { - match (self.upper_half, other.upper_half) { - (true, false) => Some(Ordering::Greater), - (false, true) => Some(Ordering::Less), - _ => match (self. divident as f64 / self.divisor as f64) - (other.divident as f64 / other.divisor as f64) { - n if n < 0.0 => Some(Ordering::Greater), - p if p > 0.0 => Some(Ordering::Less), - _ => Some(Ordering::Equal), - } + match self.quadrant.cmp(&(other.quadrant)) { + Ordering::Equal => Some((other.divident * self.divisor).cmp(&(self.divident * other.divisor))), + diff => Some(diff), } } } @@ -52,49 +53,15 @@ impl RationalAngle { pub fn run(input: &str) -> (usize, usize) { let asteroids: Vec<(usize, usize)> = input.lines().enumerate().flat_map(|(y, line)| line.chars().enumerate().filter(|(_x, c)| *c == '#').map(|(x, _c)| (x, y)).collect::>()).collect(); - // let mut angles: Vec> = asteroids.iter().map(|a| asteroids.iter().filter(|other| *other != a).map(|other| reduced_angle(*a, *other)).collect()).collect(); - let mut angles: Vec> = asteroids.iter().map(|a| asteroids.iter().filter(|other| *other != a).map(|other| RationalAngle::from_vector(*a, *other)).collect()).collect(); - // for asteroid in angles.iter_mut() { - // asteroid.sort_by(rotation_sort); - // asteroid.dedup(); - // } + let angles: Vec> = asteroids.iter().map(|a| asteroids.iter().filter(|other| *other != a).map(|other| RationalAngle::from_vector(*a, *other)).collect()).collect(); let (idx, first) = angles.iter().enumerate().max_by_key(|(_idx, a)| a.len()).unwrap(); let angle = first.iter().nth(199).unwrap(); - let second = (0, 0); - // let second = (1..).map(|i| ((asteroids[idx].0 as isize + i * angle.divident) as usize, (asteroids[idx].1 as isize + i * angle.divisor as isize) as usize)) - // .find(|a| asteroids.contains(a)) - // .unwrap(); + let second = (1..).map(|i| ((asteroids[idx].0 as isize + i * angle.divident) as usize, (asteroids[idx].1 as isize + i * angle.divisor) as usize)) + .find(|a| asteroids.contains(a)) + .unwrap(); (first.len(), (second.0*100 + second.1)) } -fn rotation_sort(lhs: &(isize, isize), rhs: &(isize, isize)) -> Ordering { - if lhs == rhs { - return Ordering::Equal; - } - match (lhs.0.signum(), rhs.0.signum()) { - (-1, 1) => Ordering::Greater, - (1, -1) => Ordering::Less, - (0, -1) =>Ordering::Less, - (-1, 0) => Ordering::Greater, - (0, 1) => if lhs.1.signum() == 1 { Ordering::Less } else { Ordering::Greater }, - (1, 0) => if rhs.1.signum() == 1 { Ordering::Greater } else { Ordering::Less }, - (0, 0) => match (lhs.1.signum(), rhs.1.signum()) { - (1, 1) | (-1, -1) => Ordering::Equal, - (1, -1) => Ordering::Less, - (-1, 1) => Ordering::Greater, - _ => panic!("Unable to sort {lhs:?} and {rhs:?}"), - }, - _ => match (lhs.1.signum(), rhs.1.signum()) { - (1, 1) | (-1, -1) => match (lhs.0 as f64 / lhs.1 as f64) - (rhs.0 as f64 / rhs.1 as f64) { - n if n < 0.0 => Ordering::Greater, - p if p > 0.0 => Ordering::Less, - _ => panic!("Unexpected sorting of {lhs:?} and {rhs:?}: Equal"), - }, - _ => (lhs.0.signum()*lhs.1.signum()).cmp(&(lhs.0.signum()*rhs.1.signum())) - }, - } -} - fn gcd(lhs: isize, rhs: isize) -> isize { if lhs == 0 { return rhs.abs(); @@ -108,13 +75,6 @@ fn gcd(lhs: isize, rhs: isize) -> isize { (1..=a.min(b)).rev().find(|i| a%i == 0 && b%i == 0).unwrap() } -fn reduced_angle(lhs: (usize, usize), rhs: (usize, usize)) -> (isize, isize) { - let x = rhs.0 as isize - lhs.0 as isize; - let y = rhs.1 as isize - lhs.1 as isize; - - (x/gcd(x,y), y/gcd(x,y)) -} - #[cfg(test)] mod tests { use super::*; @@ -124,11 +84,12 @@ mod tests { read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string() } - // #[test] - // fn test_sample() { - // let sample_input = read_file("tests/sample_input"); - // assert_eq!(run(&sample_input), (33, 0)); - // } + #[test] + #[ignore = "The sample doesn't have enough asteroids to run part 2."] + fn test_sample() { + let sample_input = read_file("tests/sample_input"); + assert_eq!(run(&sample_input), (33, 0)); + } #[test] fn test_challenge() {