Advertisement
mykdavies

AOC 2022 Day 15

Dec 15th, 2022 (edited)
1,125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 3.63 KB | None | 0 0
  1. /// Sensors can see closest beacons, which means others may be out there.
  2. /// 1) find 'clear' points on a given line.
  3. /// 2) find only 'unclear' point in a given area.
  4. ///Sensor at x=2, y=18: closest beacon is at x=-2, y=15
  5. import 'dart:math';
  6. import 'package:collection/collection.dart';
  7. import 'package:more/more.dart';
  8.  
  9. class Cover {
  10.   int start, end;
  11.   Cover(this.start, this.end);
  12.   bool contains(int i) => i >= start && i <= end;
  13. }
  14.  
  15. var sensorRanges = <Point<int>, int>{};
  16. var beacons = <Point<int>>{};
  17. int dist(Point<int> p1, Point<int> p2) =>
  18.     (p1.x - p2.x).abs() + (p1.y - p2.y).abs();
  19.  
  20. addLines(List<String> lines) {
  21.   sensorRanges = <Point<int>, int>{};
  22.   beacons = <Point<int>>{};
  23.  
  24.   var re = RegExp(r'(-?\d+)');
  25.   lines
  26.       .map((e) => re.allMatches(e).map((m) => int.parse(m.group(1)!)).toList())
  27.       .forEach((e) {
  28.     var ps = Point(e[0], e[1]), pb = Point(e[2], e[3]);
  29.     sensorRanges[ps] = dist(ps, pb);
  30.     beacons.add(pb);
  31.   });
  32. }
  33.  
  34. clearCovered() {
  35.   for (var s in sensorRanges.entries) {
  36.     for (var t in sensorRanges.entries) {
  37.       if (s.key == t.key) continue;
  38.       if (t.value <= s.value - dist(s.key, t.key)) {
  39.         sensorRanges.remove(t);
  40.       }
  41.     }
  42.   }
  43. }
  44.  
  45. var covers = <Cover>{};
  46. addCover(Cover c) {
  47.   for (var t in covers.toList()) {
  48.     if (c.end < t.start - 1 || c.start > t.end + 1) continue;
  49.     covers.remove(t);
  50.     c = Cover(min(c.start, t.start), max(c.end, t.end));
  51.   }
  52.   covers.add(c);
  53. }
  54.  
  55. void buildCovers(int y) {
  56.   covers = <Cover>{};
  57.   for (var s in sensorRanges.keys) {
  58.     var d = sensorRanges[s]!;
  59.     var halfWidth = d - (s.y - y).abs();
  60.     if (halfWidth < 0) continue;
  61.     var r = Cover(s.x - halfWidth, s.x + halfWidth);
  62.     addCover(r);
  63.   }
  64. }
  65.  
  66. part1(int y, List<String> lines) {
  67.   addLines(lines);
  68.   clearCovered();
  69.  
  70.   buildCovers(y);
  71.   var seen = 0;
  72.   var bs = beacons.where((e) => e.y == y);
  73.   for (var c in covers) {
  74.     seen += c.end - c.start + 1;
  75.     for (var b in bs) {
  76.       if (c.contains(b.x)) seen -= 1;
  77.     }
  78.   }
  79.   return seen;
  80. }
  81.  
  82. int part2(int size, List<String> lines) {
  83.   addLines(lines);
  84.   clearCovered();
  85.  
  86.   for (var y in 0.to(size + 1)) {
  87.     buildCovers(y);
  88.     if (covers.length == 1) continue;
  89.     return covers.map((e) => e.end + 1).min * 4000000 + y;
  90.   }
  91.   return 0; // never!
  92. }
  93.  
  94. var os = [Point(1, 0), Point(0, -1), Point(-1, 0), Point(0, 1), Point(1, 0)];
  95. // Find the edges just out of reach of each beacon, for jsut one cell to be
  96. // not covered, it must be at the intersection of some of these lines.
  97. int part2Edges(int size, List<String> lines) {
  98.   addLines(lines);
  99.   var edges = <List<int>>{};
  100.   for (var s in sensorRanges.keys) {
  101.     var d = sensorRanges[s]! + 1;
  102.     for (var off in os.window(2)) {
  103.       var p1 = s + off.first * d;
  104.       var p2 = s + off.last * d;
  105.       var grad = (p2.x - p1.x) ~/ (p2.y - p1.y); // 1 or -1
  106.       var org = p1.y - p1.x * grad;
  107.       edges.add([grad, org]);
  108.     }
  109.   }
  110.  
  111.   // Build intersections.
  112.   var intersections = <Point<int>>{};
  113.   for (var l in edges.where((e) => e.first == 1)) {
  114.     for (var r in edges.where((e) => e.first == -1)) {
  115.       int x = (r.last - l.last) ~/ 2;
  116.       int y = x * l.first + l.last;
  117.       if (x >= 0 && x <= size && y >= 0 && y <= size) {
  118.         intersections.add(Point(x, y));
  119.       }
  120.     }
  121.   }
  122.   // Remove any within range of a beacon.
  123.   for (var s in sensorRanges.keys) {
  124.     var d = sensorRanges[s]!;
  125.     for (var i in intersections.toSet()) {
  126.       if (dist(s, i) <= d) intersections.remove(i);
  127.     }
  128.   }
  129.   if (intersections.length != 1) return -1;
  130.   return intersections.map((e) => e.x * 4000000 + e.y).first;
  131. }
  132.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement