Browse Source

add day15

niels 2 years ago
parent
commit
e38960eee2
2 changed files with 176 additions and 0 deletions
  1. 160 0
      src/bin/day15.rs
  2. 16 0
      test_inputs/day15.txt

+ 160 - 0
src/bin/day15.rs

@@ -0,0 +1,160 @@
+use aoc2022_niels_overkamp::common::{self, AOCResult};
+use nom::{
+    bytes::complete::tag,
+    character::{complete::i128 as i128_parser, streaming::char},
+    combinator::all_consuming,
+    error::Error,
+    sequence::{preceded, separated_pair},
+    Finish, Parser,
+};
+use std::{
+    collections::{HashMap, HashSet},
+    mem,
+    ops::Range,
+};
+
+const DAY: &str = "day15";
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    common::run(DAY, &run)
+}
+
+type Num = i128;
+type Point = (Num, Num);
+type Line = (Point, Point);
+
+fn intersection(((x1, y1), (x2, y2)): Line, ((x3, y3), (x4, y4)): Line) -> Option<Point> {
+    let d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+
+    let tn = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4);
+    let un = (x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2);
+    let b = if d > 0 {
+        tn > d || un > d || tn < 0 || un < 0
+    } else {
+        tn < d || un < d || tn > 0 || un > 0
+    };
+    if b || d == 0 {
+        return None;
+    }
+    let temp = tn * (x2 - x1);
+    if temp % d != 0 {
+        return None;
+    }
+
+    Some((x1 + tn * (x2 - x1) / d, y1 + tn * (y2 - y1) / d))
+}
+
+pub fn run(input: &Vec<String>) -> AOCResult {
+    let mut line_parser = {
+        let v_parser = |c| preceded(char(c).and(char('=')), i128_parser);
+        let point_parser = || separated_pair(v_parser('x'), tag(", "), v_parser('y'));
+        let sensor_parser = preceded(tag("Sensor at "), point_parser());
+        let beacon_parser = preceded(tag("closest beacon is at "), point_parser());
+        let line_parser = separated_pair(sensor_parser, tag(": "), beacon_parser);
+        all_consuming(line_parser)
+    };
+
+    let check_height = input.last().unwrap().parse::<Num>()?;
+
+    let check_size = check_height * 2;
+    let check_area = 0..=check_size;
+    let mut l_lines = HashSet::new();
+    let mut r_lines = HashSet::new();
+    let mut oor_intersections: HashMap<Point, usize> = HashMap::new();
+    let mut sensors = vec![];
+
+    let mut check_line = HashSet::new();
+    let mut check_line_beacons = HashSet::new();
+
+    let filter_add = |i: Option<Point>, i_map: &mut HashMap<Point, usize>| {
+        i.filter(|i| check_area.contains(&i.0) && check_area.contains(&i.1))
+            .map(|i| *i_map.entry(i).or_default() += 1)
+    };
+
+    for line in &input[..input.len() - 1] {
+        let (sensor, beacon) = line_parser(line.as_str())
+            .finish()
+            .map(|(_, l)| l)
+            .map_err(|e: Error<&str>| e.to_string())?;
+
+        let range = sensor.0.abs_diff(beacon.0) + sensor.1.abs_diff(beacon.1);
+        let dist = check_height.abs_diff(sensor.1);
+
+        let range = range as Num;
+        let dist = dist as Num;
+
+        // Part 2
+
+        sensors.push((sensor, range));
+
+        let corners = [
+            (sensor.0 + range + 1, sensor.1),
+            (sensor.0, sensor.1 + range + 1),
+            (sensor.0 - range - 1, sensor.1),
+            (sensor.0, sensor.1 - range - 1),
+        ];
+
+        let r_line1 = (corners[0], corners[1]);
+        let l_line1 = (corners[1], corners[2]);
+        let r_line2 = (corners[2], corners[3]);
+        let l_line2 = (corners[3], corners[0]);
+
+        for l_line in l_lines.iter() {
+            filter_add(intersection(*l_line, r_line1), &mut oor_intersections);
+            filter_add(intersection(*l_line, r_line2), &mut oor_intersections);
+        }
+        for r_line in r_lines.iter() {
+            filter_add(intersection(*r_line, l_line1), &mut oor_intersections);
+            filter_add(intersection(*r_line, l_line2), &mut oor_intersections);
+        }
+
+        l_lines.extend(&[l_line1, l_line2]);
+        r_lines.extend(&[r_line1, r_line2]);
+
+        // Part 1
+        let radius = (range - dist).max(-1);
+        check_line.extend(
+            Range {
+                start: (sensor.0 - radius),
+                end: (sensor.0 + radius) + 1,
+            }
+            .into_iter(),
+        );
+
+        if beacon.1 == check_height {
+            check_line_beacons.insert(beacon.0);
+        }
+    }
+
+    let (s, r): (Vec<_>, Vec<_>) = sensors.clone().into_iter().unzip();
+    let (sx, sy): (Vec<_>, Vec<_>) = s.into_iter().unzip();
+
+    let possible_locations = oor_intersections.iter().filter(|(_, n)| **n >= 4);
+    println!("l={:?}", possible_locations.clone().map(|(i, _)| i).collect::<Vec<_>>().as_slice());
+    let mut location = None;
+    for (pos, n) in possible_locations {
+        let mut in_range = false;
+        for (sensor, range) in sensors.iter() {
+            if (sensor.0.abs_diff(pos.0) + sensor.1.abs_diff(pos.1)) as Num <= *range {
+                in_range = true;
+                break;
+            }
+        }
+        if !in_range {
+            location = Some(pos);
+            break;
+        }
+    }
+
+    let location = location.ok_or("No suitable location found")?;
+    let tuning_frequency = location.0 * check_size + location.1;
+
+    let count = check_line.difference(&check_line_beacons).count();
+
+    Ok([Some(count.to_string()), Some(tuning_frequency.to_string())])
+}
+
+#[test]
+pub fn test_day15() {
+    assert!(common::run_test(DAY, &run))
+}

+ 16 - 0
test_inputs/day15.txt

@@ -0,0 +1,16 @@
+Sensor at x=2, y=18: closest beacon is at x=-2, y=15
+Sensor at x=9, y=16: closest beacon is at x=10, y=16
+Sensor at x=13, y=2: closest beacon is at x=15, y=3
+Sensor at x=12, y=14: closest beacon is at x=10, y=16
+Sensor at x=10, y=20: closest beacon is at x=10, y=16
+Sensor at x=14, y=17: closest beacon is at x=10, y=16
+Sensor at x=8, y=7: closest beacon is at x=2, y=10
+Sensor at x=2, y=0: closest beacon is at x=2, y=10
+Sensor at x=0, y=11: closest beacon is at x=2, y=10
+Sensor at x=20, y=14: closest beacon is at x=25, y=17
+Sensor at x=17, y=20: closest beacon is at x=21, y=22
+Sensor at x=16, y=7: closest beacon is at x=15, y=3
+Sensor at x=14, y=3: closest beacon is at x=15, y=3
+Sensor at x=20, y=1: closest beacon is at x=15, y=3
+10
+26$291