From 75706b14e36164c5c7f975321b9a4e82fec30826 Mon Sep 17 00:00:00 2001
From: Joe Ardent <code@ardent.nebcorp.com>
Date: Thu, 2 Jan 2025 16:43:36 -0800
Subject: [PATCH] day8, part2

---
 day08/src/main.rs | 101 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 83 insertions(+), 18 deletions(-)

diff --git a/day08/src/main.rs b/day08/src/main.rs
index 8a01568..7a9e91b 100644
--- a/day08/src/main.rs
+++ b/day08/src/main.rs
@@ -26,7 +26,7 @@ fn pt1(input: &str) -> usize {
                 if a1 == a2 {
                     continue;
                 }
-                for antinode in board.antinodes(*a1, *a2) {
+                for antinode in board.antinodes(*a1, *a2, false) {
                     antinodes.insert(antinode);
                 }
             }
@@ -40,9 +40,35 @@ fn pt1(input: &str) -> usize {
 }
 
 fn pt2(input: &str) -> usize {
-    let mut total = 0;
+    let mut board = Board::new(input);
+    let mut antinodes = HashSet::new();
 
-    total
+    for f in board.freqs() {
+        for a1 in board.antennae[&f].iter() {
+            for a2 in board.antennae[&f].iter() {
+                if a1 == a2 {
+                    continue;
+                }
+                let nodes = board.antinodes(*a1, *a2, true);
+                antinodes.extend(nodes.into_iter());
+            }
+        }
+    }
+    for &antinode in antinodes.iter() {
+        board.set(antinode, Cell::Antinode);
+    }
+    println!("{board}");
+    antinodes.len()
+}
+
+fn gcd(mut a: usize, mut b: usize) -> usize {
+    let mut t = 0;
+    while b != 0 {
+        t = b;
+        b = a % b;
+        a = t;
+    }
+    a
 }
 
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -124,31 +150,61 @@ impl Board {
         false
     }
 
-    fn antinodes(&self, a1: Loc, a2: Loc) -> Vec<Loc> {
-        let dy = (a1.0 as i64 - a2.0 as i64).unsigned_abs() as usize;
-        let dx = (a1.1 as i64 - a2.1 as i64).unsigned_abs() as usize;
+    fn antinodes(&self, a1: Loc, a2: Loc, pt2: bool) -> HashSet<Loc> {
+        let mut dy = (a1.0 as i64 - a2.0 as i64).unsigned_abs() as usize;
+        let mut dx = (a1.1 as i64 - a2.1 as i64).unsigned_abs() as usize;
+
         // row 0 is at the top
         let (top, bottom) = if a1.0 <= a2.0 { (a1, a2) } else { (a2, a1) };
         let (left, right) = if a1.1 <= a2.1 { (a1, a2) } else { (a2, a1) };
-        let mut antinodes = Vec::new();
+        let mut antinodes = HashSet::new();
 
         let ny_top = top.0.wrapping_sub(dy);
         let ny_bot = bottom.0 + dy;
         let nx_left = left.1.wrapping_sub(dx);
         let nx_right = right.1 + dx;
+        let slopes_up = top == right;
 
-        let (n1, n2) = match (a1, a2) {
-            _ if top == left => (Loc(ny_top, nx_left), Loc(ny_bot, nx_right)),
-            _ if top == right => (Loc(ny_top, nx_right), Loc(ny_bot, nx_left)),
-            _ if bottom == left => (Loc(ny_bot, nx_left), Loc(ny_top, nx_right)),
-            _ => (Loc(ny_bot, nx_right), Loc(ny_top, nx_left)),
-        };
+        if pt2 {
+            let g = gcd(dy, dx);
+            dy /= g;
+            dx /= g;
 
-        if n1.0 < self.bottom && n1.1 < self.right {
-            antinodes.push(n1);
-        }
-        if n2.0 < self.bottom && n2.1 < self.right {
-            antinodes.push(n2);
+            // start at the left and move right
+            let mut loc = left;
+            while loc.0 < self.bottom && loc.1 < self.right {
+                antinodes.insert(loc);
+                loc.1 += dx;
+                if slopes_up {
+                    loc.0 = loc.0.wrapping_sub(dy);
+                } else {
+                    loc.0 += dy;
+                }
+            }
+
+            // now start at the right and move left
+            let mut loc = right;
+            while loc.0 < self.bottom && loc.1 < self.right {
+                antinodes.insert(loc);
+                loc.1 = loc.1.wrapping_sub(dx);
+                if slopes_up {
+                    loc.0 += dy;
+                } else {
+                    loc.0 = loc.0.wrapping_sub(dy);
+                }
+            }
+        } else {
+            let (n1, n2) = if slopes_up {
+                (Loc(ny_bot, nx_left), Loc(ny_top, nx_right))
+            } else {
+                (Loc(ny_top, nx_left), Loc(ny_bot, nx_right))
+            };
+            if n1.0 < self.bottom && n1.1 < self.right {
+                antinodes.insert(n1);
+            }
+            if n2.0 < self.bottom && n2.1 < self.right {
+                antinodes.insert(n2);
+            }
         }
 
         antinodes
@@ -203,4 +259,13 @@ mod test {
     fn p2() {
         assert_eq!(34, pt2(INPUT));
     }
+
+    #[test]
+    fn g() {
+        let a = gcd(12, 30);
+        assert_eq!(a, 6);
+
+        let b = gcd(51, 17);
+        assert_eq!(b, 17);
+    }
 }