mykdavies

AOC2021 Day22

Dec 22nd, 2021 (edited)
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 5.71 KB | None | 0 0
  1. /// Turn 3x3x3 blocks of light on and off as instructed.
  2. /// First limited to -50 to 50 in each direction.
  3. /// Then it most definitely isn't :-(
  4. import 'dart:io';
  5. import 'package:vector_math/vector_math.dart';
  6. import 'package:collection/collection.dart';
  7.  
  8. var mind = -50, maxd = 50;
  9.  
  10. var nre = RegExp(r'[^0-9-]+');
  11.  
  12. /// Obsolete semi-naive approach for part 1.
  13. // runLine1(String s, Set<Vector3> grid) {
  14. //   //on x=10..12,y=10..12,z=10..12
  15. //   var c = s.split(nre).skip(1).map(double.parse).toList();
  16. //   var on = s[1] == 'n';
  17. //   for (var x in c[0].to(c[1] + 1)) {
  18. //     if (x < mind || x > maxd) continue;
  19. //     for (var y in c[2].to(c[3] + 1)) {
  20. //       if (y < mind || y > maxd) continue;
  21. //       for (var z in c[4].to(c[5] + 1)) {
  22. //         if (z < mind || z > maxd) continue;
  23. //         var v = Vector3(x, y, z);
  24. //         //if (!safe(v)) continue;
  25. //         if (on) {
  26. //           grid.add(v);
  27. //         } else {
  28. //           grid.remove(v);
  29. //         }
  30. //       }
  31. //     }
  32. //   }
  33. // }
  34.  
  35. /// A Cuboid is defined by its lower left front corner and its
  36. /// upper right back corner. If it intersects with another cuboid
  37. /// we can cleave it along each of the planes of that intersection.
  38. class Cuboid {
  39.   late Vector3 lo;
  40.   late Vector3 hi;
  41.   late bool on;
  42.   var overlaps = <Cuboid>[];
  43.   Cuboid(this.lo, this.hi, this.on);
  44.   @override
  45.   toString() => '[$lo $hi]';
  46.  
  47.   @override
  48.   get hashCode => Object.hash(lo, hi);
  49.  
  50.   @override
  51.   bool operator ==(Object other) =>
  52.       other is Cuboid && other.lo == lo && other.hi == hi;
  53.  
  54.   bool overlapsWith(Cuboid other) =>
  55.       (other.hi.x >= lo.x && other.lo.x <= hi.x) &&
  56.       (other.hi.y >= lo.y && other.lo.y <= hi.y) &&
  57.       (other.hi.z >= lo.z && other.lo.z <= hi.z);
  58.  
  59.   bool isIn(p0, p1, p2) => p0 >= p1 && p0 <= p2;
  60.  
  61.   bool get isEmpty => lo.x > hi.x || lo.y > hi.y || lo.z > hi.z;
  62.  
  63.   Cuboid? cleaveOnLeftAt(double x) {
  64.     if (!isIn(x, lo.x, hi.x)) return null;
  65.     Cuboid n = Cuboid(Vector3(lo.x, lo.y, lo.z), Vector3(x, hi.y, hi.z), true);
  66.     lo.x = x + 1;
  67.     return n;
  68.   }
  69.  
  70.   Cuboid? cleaveOnRightAt(double x) {
  71.     if (!isIn(x, lo.x, hi.x)) return null;
  72.     Cuboid n = Cuboid(Vector3(x, lo.y, lo.z), Vector3(hi.x, hi.y, hi.z), true);
  73.     hi.x = x - 1;
  74.     return n;
  75.   }
  76.  
  77.   Cuboid? cleaveOnBottomAt(double y) {
  78.     if (!isIn(y, lo.y, hi.y)) return null;
  79.     Cuboid n = Cuboid(Vector3(lo.x, lo.y, lo.z), Vector3(hi.x, y, hi.z), true);
  80.     lo.y = y + 1;
  81.     return n;
  82.   }
  83.  
  84.   Cuboid? cleaveOnTopAt(double y) {
  85.     if (!isIn(y, lo.y, hi.y)) return null;
  86.     Cuboid n = Cuboid(Vector3(lo.x, y, lo.z), Vector3(hi.x, hi.y, hi.z), true);
  87.     hi.y = y - 1;
  88.     return n;
  89.   }
  90.  
  91.   Cuboid? cleaveOnFrontAt(double z) {
  92.     if (!isIn(z, lo.z, hi.z)) return null;
  93.     Cuboid n = Cuboid(Vector3(lo.x, lo.y, lo.z), Vector3(hi.x, hi.y, z), true);
  94.     lo.z = z + 1;
  95.     return n;
  96.   }
  97.  
  98.   Cuboid? cleaveOnBackAt(double z) {
  99.     if (!isIn(z, lo.z, hi.z)) return null;
  100.     Cuboid n = Cuboid(Vector3(lo.x, lo.y, z), Vector3(hi.x, hi.y, hi.z), true);
  101.     hi.z = z - 1;
  102.     return n;
  103.   }
  104.  
  105.   List<Cuboid> gatherShards(Cuboid other) {
  106.     var rs = <Cuboid>[];
  107.     Cuboid? t = cleaveOnLeftAt(other.lo.x - 1);
  108.     if (t != null) rs.add(t);
  109.     if (isEmpty) return rs;
  110.  
  111.     t = cleaveOnRightAt(other.hi.x + 1);
  112.     if (t != null) rs.add(t);
  113.     if (isEmpty) return rs;
  114.  
  115.     t = cleaveOnBottomAt(other.lo.y - 1);
  116.     if (t != null) rs.add(t);
  117.     if (isEmpty) return rs;
  118.  
  119.     t = cleaveOnTopAt(other.hi.y + 1);
  120.     if (t != null) rs.add(t);
  121.     if (isEmpty) return rs;
  122.  
  123.     t = cleaveOnFrontAt(other.lo.z - 1);
  124.     if (t != null) rs.add(t);
  125.     if (isEmpty) return rs;
  126.  
  127.     t = cleaveOnBackAt(other.hi.z + 1);
  128.     if (t != null) rs.add(t);
  129.  
  130.     return rs;
  131.   }
  132. }
  133.  
  134. runLine2(List<String> lines) {
  135.   //on x=10..12,y=10..12,z=10..12
  136.   var rs = <Cuboid>[];
  137.   for (var l in lines) {
  138.     var on = l[1] == 'n';
  139.     var c = l.split(nre).skip(1).map(double.parse).toList();
  140.     var v0 = Vector3(c[0], c[2], c[4]);
  141.     var v1 = Vector3(c[1], c[3], c[5]);
  142.     var r = Cuboid(v0, v1, on);
  143.     // We only save ranges of 'on' lights. We use 'off' ranges to split those
  144.     // 'on' ranges.
  145.     if (on) {
  146.       rs.add(r);
  147.       continue;
  148.     }
  149.     // We have an off.
  150.     for (var re in rs.toList() /*copy*/) {
  151.       if (!re.overlapsWith(r)) continue;
  152.       // We will save all the good parts, so remove the stub
  153.       rs.remove(re);
  154.       rs.addAll(re.gatherShards(r));
  155.     }
  156.   }
  157.   return rs;
  158. }
  159.  
  160. /// Count how many lights should be on. Many of the cuboids will overlap,
  161. /// so we need to find those overlaps and deal with them. I use the same
  162. /// approach as above: cleave the cuboids at the intersection planes and
  163. /// collect the (up to 6, but normally 1) resulting cuboids.
  164. int countOn(List<Cuboid> cubes) {
  165.   var dirtys = cubes.skip(1).toList();
  166.   var cleans = [cubes.first];
  167.   while (dirtys.isNotEmpty) {
  168.     //print(dirtys.length);
  169.     var dirty = dirtys.removeLast();
  170.     if (cleans.none((c) => c.overlapsWith(dirty))) {
  171.       cleans.add(dirty);
  172.       continue;
  173.     }
  174.     // Find an overlap, and gather the shards
  175.     var clean = cleans.firstWhere((c) => c.overlapsWith(dirty));
  176.     dirtys.addAll(dirty.gatherShards(clean));
  177.   }
  178.   return cleans
  179.       .map((c) =>
  180.           (c.hi.x - c.lo.x + 1) * (c.hi.y - c.lo.y + 1) * (c.hi.z - c.lo.z + 1))
  181.       .sum
  182.       .toInt();
  183. }
  184.  
  185. main() {
  186.   var lines = File('data/data22_01.txt').readAsLinesSync();
  187.   var t = DateTime.now();
  188.   var cubes = runLine2(lines.take(20).toList()); // initialisation region
  189.   print(countOn(cubes)); // 596598
  190.   cubes = runLine2(lines);
  191.   print(countOn(cubes)); // 1199121349148621
  192.   print('${DateTime.now().difference(t).inMilliseconds} milliseconds');
  193. }
  194.  
Add Comment
Please, Sign In to add comment